הגדרת רשתות Ethernet פנימיות

מערכת ההפעלה Android Auto מגרסה 13 ומעלה כוללת תכונות שמאפשרות להגדיר ולנהל רשתות Ethernet. איור 1 מציג תרשים רשת לדוגמה של מכונית:

חיבור לרשת ב-Android Auto

איור 1. רשתות ב-Android Auto.

באיור הזה מוצגות שיטות להפעלת אפליקציית רשת של יצרן ציוד מקורי (OEM) במחלקה EthernetManager כדי להגדיר ולנהל רשתות Ethernet מובנות (eth0.1,‏ eth0.2 ו-eth0.3). החלק הנותר של איור 1 לא נכלל במסמך הזה.

קביעת הגדרות ברירת המחדל של רשת Ethernet

כדי להגדיר את הגדרות הרשת כברירת מחדל, משתמשים בשכבת-על של משאבים config_ethernet_interfaces:

<string-array translatable="false" name="config_ethernet_interfaces">
        <!--
        <item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
        <item>eth2;;ip=192.168.0.11/24</item>
        <item>eth3;12,13,14,15;ip=192.168.0.12/24;1</item>
        -->
    </string-array>

בדוגמה הזו מוצגת שכבת העל של המשאבים מ-config.xml.config_ethernet_interfaces

נקודות חשובות לגבי הקוד

  • eth1, eth2 ו-eth3 הם השמות של ממשקי הרשת שמוגדרים.
  • המספרים העוקבים 12, 13, 14, 15 מייצגים הפעלה של יכולות של הרשת.
  • הפרמטרים ip=,‏ gateway= ו-dns משמשים להגדרת כתובת ה-IP הראשונית, שער ו-DNS לרשת.

הפעלה או השבתה של ממשק רשת

כדי להפעיל ממשק רשת, מתקשרים אל EthernetManager.enableInterface():

public final class InterfaceEnabler {
    private final Context mApplicationContext;
    private final EthernetManager mEthernetManager;
    private final OutcomeReceiver<String, EthernetNetworkManagementException> mOutcomeReceiver;

    public InterfaceEnabler(Context applicationContext,
            OutcomeReceiver<String, EthernetNetworkManagementException> outcomeReceiver) {
        mApplicationContext = applicationContext;
        mEthernetManager = applicationContext.getSystemService(EthernetManager.class);
        mOutcomeReceiver = outcomeReceiver;
    }

    public void enableInterface(String ifaceName) {
        mEthernetManager.enableInterface(ifaceName,
                mApplicationContext.getMainExecutor(),
                mOutcomeReceiver);
    }
}

נקודות חשובות לגבי הקוד

  • ifaceName הוא שם ממשק הרשת שרוצים להפעיל.
  • getMainExecutor() מחזירה את הקשר של האפליקציה.
  • OutcomeReceiver הוא קריאה חוזרת שמשמשת להעברת מידע על השלמת הפעולה. אם הפעולה הושלמה בהצלחה, מוחזר שם הרשת המעודכן. אם הפעולה נכשלה, מוחזר הערך EthernetNetworkManagementException.

כשממשק רשת מופעל, הוא משתמש בהגדרה שנקבעה על ידי EthernetManager.updateConfiguration(). אם EthernetManager.updateConfiguration() לא הגדיר תצורה, ממשק הרשת משתמש בכיסוי המשאבים config_ethernet_interfaces או בהגדרות ברירת המחדל של רשת האתרנט אם כיסוי לא זמין.

כדי להשבית ממשק רשת, מתקשרים אל EthernetManager.disableInterface():

public final class InterfaceEnabler {
    private final Context mApplicationContext;
    private final EthernetManager mEthernetManager;
    private final OutcomeReceiver<String, EthernetNetworkManagementException> mOutcomeReceiver;

    public InterfaceEnabler(Context applicationContext,
            OutcomeReceiver<String, EthernetNetworkManagementException> outcomeReceiver) {
        mApplicationContext = applicationContext;
        mEthernetManager = applicationContext.getSystemService(EthernetManager.class);
        mOutcomeReceiver = outcomeReceiver;
    }

    public void disableInterface(String ifaceName) {
        mEthernetManager.disableInterface(ifaceName,
                mApplicationContext.getMainExecutor(),
                mOutcomeReceiver);
    }
}

נקודות חשובות לגבי הקוד

  • ifaceName הוא השם של ממשק הרשת שרוצים להשבית.
  • getMainExecutor() מחזירה את הקשר של האפליקציה.
  • OutcomeReceiver הוא קריאה חוזרת שמשמשת להעברת מידע על השלמת הפעולה. אם הפעולה הושלמה בהצלחה, מוחזר שם הרשת המעודכן. אם הפעולה נכשלה, מוחזר הערך EthernetNetworkManagementException.

עדכון הגדרת הרשת

כדי לעדכן את ההגדרות של רשת Ethernet, קוראים לפונקציה EthernetManager.updateConfiguration():

public final class ConfigurationUpdater {
    private final Context mApplicationContext;
    private final EthernetManager mEthernetManager;
    private final OutcomeReceiver<String, EthernetNetworkManagementException> mCallback;

    public ConfigurationUpdater(Context applicationContext,
            OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
        mApplicationContext = applicationContext;
        mEthernetManager = applicationContext.getSystemService(EthernetManager.class);
        mCallback = callback;
    }

    public void updateNetworkConfiguration(String packageNames,
            String ipConfigurationText,
            String networkCapabilitiesText,
            String interfaceName)
            throws IllegalArgumentException, PackageManager.NameNotFoundException {

        EthernetNetworkUpdateRequest request = new EthernetNetworkUpdateRequest.Builder()
                .setIpConfiguration(getIpConfiguration(ipConfigurationText))
                .setNetworkCapabilities(getCapabilities(
                        interfaceName, networkCapabilitiesText, packageNames))
                .build();

        mEthernetManager.updateConfiguration(interfaceName, request,
                mApplicationContext.getMainExecutor(), mCallback);

    }
}

נקודות חשובות לגבי הקוד

  • getCapabilities() היא שיטת עזר שמקבלת את היכולות הנוכחיות של הרשת ומפעילה את convertToUIDs() כדי להמיר שמות חבילות שקלים לקריאה למזהה ייחודי (UID) של Linux. בדרך כלל, אתם לא יודעים מראש את מזהי ה-UID של החבילות המשויכות. לכן, אם רוצים להשתמש ב-EthernetManager.updateConfiguration() כדי להגביל את הגישה לקבוצת משנה של אפליקציות, צריך להשתמש במזהי המשתמשים שלהן.
  • request היא ההגדרה שתשמש לרשת הפנימית. הבקשה יכולה להכיל הגדרות חדשות של תצורת ה-IP והיכולות של הרשת. אם הרשת רשומה במערך הקישוריות, היא מתעדכנת בהתאם להגדרה. ההגדרה הזו לא נשמרת אחרי הפעלה מחדש.
  • getMainExecutor() מחזירה את ה-executor שבו מופעל ה-listener.
  • mCallback הוא ה-callback שמשמש לתקשורת של השלמת ההחזרה של שם הרשת המעודכן במקרה של הצלחה או EthernetNetworkManagementException במקרה של שגיאה.

יכול להיות ש-updateConfiguration() יעדכן מאפיינים של רשת שנחשבת לבלתי ניתנת לשינוי על ידי ערימת הקישוריות של Android. כדי לעדכן את המאפיינים הבלתי ניתנים לשינוי האלה, המערכת משביתה את הרשת, מעדכנת אותה ומפעילה אותה מחדש.

הגבלת רשת לקבוצת משנה של אפליקציות

אפשר להשתמש ב-EthernetManager#updateConfiguration כדי להגביל את הגישה רק לקבוצת משנה של מזהי משתמשים מורשים. אפשר להשתמש בשיטה הזו כדי לכסות תרחישי שימוש שבהם זה נדרש, למשל ברשתות פנימיות של כלי רכב שאפשר להשתמש בהן רק בחלק קטן של אפליקציות OEM.

‫Android עוקב אחרי אפליקציות בעיקר לפי ה-UID שלהן. בדוגמת הקוד הבאה מתוך UIDToPackageNameConverter.java אפשר לראות איך מקבלים סדרה של מזהי UID ממחרוזת של שמות חבילות:

public static Set<Integer> convertToUids(Context applicationContext, String packageNames)
            throws PackageManager.NameNotFoundException {
        final PackageManager packageManager = applicationContext.getPackageManager();
        final UserManager userManager = applicationContext.getSystemService(UserManager.class);

        final Set<Integer> uids = new ArraySet<>();
        final List<UserHandle> users = userManager.getUserHandles(true);

        String[] packageNamesArray = packageNames.split(",");
        for (String packageName : packageNamesArray) {
            boolean nameNotFound = true;
            packageName = packageName.trim();
            for (final UserHandle user : users) {
                try {
                    final int uid =
                            packageManager.getApplicationInfoAsUser(packageName, 0, user).uid;
                    uids.add(uid);
                    nameNotFound = false;
                } catch (PackageManager.NameNotFoundException e) {
                    // Although this may seem like an error scenario, it is OK as all packages are
                    // not expected to be installed for all users.
                    continue;
                }
            }

            if (nameNotFound) {
                throw new PackageManager.NameNotFoundException("Not installed: " + packageName);
            }
        }
        return uids;

נקודות חשובות לגבי הקוד

  • getApplicationInfoAsuser().uid משמש לאחזור ה-UID משם החבילה.
  • uids הוא מערך המספרים השלמים שנוצר.

בדוגמה הבאה של קוד ב-EthernetManagerTest.kt אפשר לראות איך לעדכן את הגדרות ממשק הרשת באמצעות מזהי UID של האפליקציות שמורשות להשתמש ברשת:

val allowedUids = setOf(Process.myUid())
        val nc = NetworkCapabilities.Builder(request.networkCapabilities)
                .setAllowedUids(allowedUids).build()
        updateConfiguration(iface, capabilities = nc).expectResult(iface.name)

נקודות חשובות לגבי הקוד

  • allowUids היא קבוצת מזהי המשתמש של האפליקציות שמורשות להשתמש ברשת.
  • updateConfiguration() מעדכן את ההגדרות כדי להגביל את הרשת לקבוצת ה-UID שצוינה.