Konfigurowanie wewnętrznych sieci Ethernet

System operacyjny Android Auto w wersji 13 lub nowszej zawiera funkcje umożliwiające konfigurowanie sieci Ethernet i zarządzanie nimi. Rysunek 1 przedstawia przykładowy diagram sieci samochodu:

Sieć w Androidzie Auto

Rysunek 1. Sieciowanie w Androidzie Auto.

Rysunek przedstawia metody wywoływania aplikacji sieciowej OEM w klasie EthernetManager, które służą do konfigurowania sieci Ethernet (eth0.1, eth0.2 i eth0.3) i zarządzania nimi. Pozostała część rysunku 1 wykracza poza zakres tego dokumentu.

Ustawianie domyślnych ustawień sieci Ethernet

Aby ustawić domyślne ustawienia sieci, użyj nakładki zasobów: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>

Ten przykład pokazuje nakładkę zasobu config_ethernet_interfacesconfig.xml.

Najważniejsze informacje o kodzie

  • eth1, eth2eth3 to nazwy konfigurowanych interfejsów sieciowych.
  • Kolejne numery 12, 13, 14, 15 oznaczają włączone możliwości sieci.
  • ip=, gateway= i dns służą do konfigurowania początkowego adresu IP, bramy i serwera DNS sieci.

Włączanie i wyłączanie interfejsu sieciowego

Aby włączyć interfejs sieci, uruchom: 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);
    }
}

Najważniejsze informacje o kodzie

  • ifaceName to nazwa interfejsu sieciowego, który ma zostać włączony.
  • getMainExecutor() zwraca kontekst aplikacji.
  • OutcomeReceiver to funkcja wywoływana z powrotem, która przekazuje informacje o wypełnieniu, zwracając zaktualizowaną nazwę sieci w przypadku powodzenia lub EthernetNetworkManagementException w przypadku błędu.

Gdy interfejs sieciowy jest włączony, korzysta z konfiguracji ustawionej przez EthernetManager.updateConfiguration(). Jeśli konfiguracja nie została ustawiona za pomocą EthernetManager.updateConfiguration(), interfejs sieciowy używa nakładki zasobów config_ethernet_interfaces lub domyślnej konfiguracji sieci Ethernet, jeśli nakładka jest niedostępna.

Aby wyłączyć interfejs sieci, wywołaj: 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);
    }
}

Najważniejsze informacje o kodzie

  • ifaceName to nazwa interfejsu sieciowego, który chcesz wyłączyć.
  • getMainExecutor() zwraca kontekst aplikacji.
  • OutcomeReceiver to funkcja wywoływana z powrotem, która przekazuje informacje o wypełnieniu, zwracając zaktualizowaną nazwę sieci w przypadku powodzenia lub EthernetNetworkManagementException w przypadku błędu.

Aktualizacja konfiguracji sieci

Aby zaktualizować konfiguracje sieci Ethernet, wywołaj: 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);

    }
}

Najważniejsze informacje o kodzie

  • getCapabilities() to metoda pomocnicza, która pobiera bieżące możliwości sieci i wywołuje funkcję convertToUIDs(), aby przekonwertować czytelne dla człowieka nazwy pakietów na unikalny identyfikator (UID) w Linuksie. Zwykle nie znasz z góry identyfikatorów UID powiązanych pakietów. Jeśli więc chcesz użyć funkcji EthernetManager.updateConfiguration(), aby ograniczyć dostęp do podzbioru aplikacji, musisz użyć ich identyfikatorów UID.
  • requestto konfiguracja używana w przypadku sieci wewnętrznej. Prośba może zawierać nowe ustawienia konfiguracji adresu IP i możliwości sieci. Jeśli sieć jest zarejestrowana w stosie łączności, jest aktualizowana zgodnie z konfiguracją. Ta konfiguracja nie jest zachowywana po ponownym uruchomieniu.
  • getMainExecutor() zwraca wykonawcę, w którym wywoływany jest listener.
  • mCallback to wywołanie zwrotne służące do przekazywania informacji o zakończeniu. W razie powodzenia zwraca ono zaktualizowaną nazwę sieci, a w razie błędu – EthernetNetworkManagementException.

updateConfiguration() może zaktualizować właściwości sieci, które są uważane za niezmienne przez pakiet Android Connectivity. Sieć jest wyłączana, aktualizowana i ponownie włączana, aby można było zaktualizować te niezmienne atrybuty.

Ograniczanie sieci do podzbioru aplikacji

Możesz użyć atrybutu EthernetManager#updateConfiguration, aby ograniczyć dostęp tylko do podzbioru dozwolonych identyfikatorów UID. Używaj tej metody w przypadkach, gdy jest to wymagane, np. w przypadku wewnętrznych sieci pojazdowych, które mogą korzystać tylko z małej podgrupy aplikacji OEM.

Android śledzi aplikacje głównie na podstawie ich identyfikatorów UID. Poniższy kod z UIDToPackageNameConverter.java pokazuje, jak uzyskać serię identyfikatorów UID z ciągu nazw pakietów:

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;

Najważniejsze informacje o kodzie

  • getApplicationInfoAsuser().uid służy do pobierania identyfikatora UID z nazwy pakietu.
  • uids to wygenerowana tablica liczb całkowitych.

Ten kod w EthernetManagerTest.kt pokazuje, jak zaktualizować konfigurację interfejsu sieciowego za pomocą identyfikatorów UID aplikacji, które mogą korzystać z sieci:

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

Najważniejsze informacje o kodzie

  • allowUids to zbiór identyfikatorów UID aplikacji, które mogą korzystać z sieci.
  • updateConfiguration() aktualizuje konfigurację, aby ograniczyć sieć do podanego zbioru identyfikatorów UID.