Configura le reti Ethernet interne

Android Auto OS 13 e versioni successive include funzionalità che ti consentono di configurare e gestire le reti Ethernet. La Figura 1 mostra un esempio di diagramma di rete per un'automobile:

Rete di Android Auto

Figura 1. Connettività di Android Auto.

Questa figura mostra i metodi di chiamata dell'app di rete OEM nella classe EthernetManager per configurare e gestire le reti Ethernet di bordo (eth0.1, eth0.2 ed eth0.3). Il resto della Figura 1 non rientra nell'ambito di questo documento.

Impostare le impostazioni di rete Ethernet predefinite

Per impostare le impostazioni di rete predefinite, utilizza il sovrapposizione della risorsa 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>

Questo esempio mostra l'overlay della risorsa config_ethernet_interfaces da config.xml.

Punti chiave del codice

  • eth1, eth2 e eth3 sono i nomi dell'interfaccia di rete in fase di configurazione.
  • I numeri consecutivi di 12, 13, 14, 15 rappresentano le funzionalità della rete attivate.
  • ip=, gateway= e dns vengono utilizzati per impostare l'indirizzo IP, il gateway e il DNS iniziali per la rete.

Attivare o disattivare un'interfaccia di rete

Per attivare un'interfaccia di rete, chiama 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);
    }
}

Punti chiave del codice

  • ifaceName è il nome dell'interfaccia di rete da attivare.
  • getMainExecutor() restituisce il contesto dell'app.
  • OutcomeReceiver è un callback utilizzato per comunicare il completamento restituendo il nome della rete aggiornato in caso di esito positivo o EthernetNetworkManagementException in caso di errore.

Quando un'interfaccia di rete è attiva, utilizza la configurazione impostata da EthernetManager.updateConfiguration(). Se non è stata impostata una configurazione da EthernetManager.updateConfiguration(), l'interfaccia di rete utilizza l'config_ethernet_interfaces overlay delle risorse o la configurazione della rete Ethernet predefinita se non è disponibile un overlay.

Per disattivare un'interfaccia di rete, chiama 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);
    }
}

Punti chiave del codice

  • ifaceName è il nome dell'interfaccia di rete da disattivare.
  • getMainExecutor() restituisce il contesto dell'app.
  • OutcomeReceiver è un callback utilizzato per comunicare il completamento restituendo il nome della rete aggiornato in caso di esito positivo o EthernetNetworkManagementException in caso di errore.

Aggiorna la configurazione di rete

Per aggiornare le configurazioni di rete Ethernet, chiama 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);

    }
}

Punti chiave del codice

  • getCapabilities() è un metodo di supporto che recupera le funzionalità di rete attuali e chiama convertToUIDs() per convertire i nomi dei pacchetti leggibili da persone in identificatori univoci (UID) di Linux. In genere, non conosci in anticipo gli UID per i pacchetti associati. Pertanto, se vuoi utilizzare EthernetManager.updateConfiguration() per limitare l'accesso a un sottoinsieme di app, devi utilizzare i relativi UID.
  • request è la configurazione da utilizzare per la rete interna. La richiesta può contenere nuove impostazioni per la configurazione IP e le funzionalità di rete. Se la rete è registrata nello stack di connettività, viene aggiornata in base alla configurazione. Questa configurazione non viene mantenuta dopo i riavvii.
  • getMainExecutor() restituisce l'executor su cui viene invocato l'ascoltatore.
  • mCallback è il callback utilizzato per comunicare il completamento, restituendo il nome della rete aggiornato in caso di esito positivo o EthernetNetworkManagementException in caso di errore.

updateConfiguration() potrebbe aggiornare le caratteristiche di una rete considerata immutabile dallo stack di connettività di Android. La rete viene riavviata, aggiornata e riavviata per aggiornare questi attributi immutabili.

Limitare una rete a un sottoinsieme di app

Puoi utilizzare EthernetManager#updateConfiguration per limitare l'accesso solo a un sottoinsieme di UID consentiti. Utilizza questo metodo per coprire i casi d'uso in cui è obbligatorio, ad esempio per le reti di veicoli interne utilizzabili solo da un piccolo sottoinsieme di app OEM.

Android monitora principalmente le app in base al loro UID. Il seguente codice di UIDToPackageNameConverter.java mostra come ottenere una serie di UID da una stringa di nomi di pacchetti:

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;

Punti chiave del codice

  • getApplicationInfoAsuser().uid viene utilizzato per recuperare l'UID dal nome del pacchetto.
  • uids è l'array di numeri interi generato.

Il seguente codice in EthernetManagerTest.kt mostra come aggiornare la configurazione dell'interfaccia di rete con gli UID delle app consentite a utilizzare la rete:

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

Punti chiave del codice

  • allowUids è l'insieme di UID di app autorizzati a utilizzare la rete.
  • updateConfiguration() aggiorna la configurazione per limitare la rete al insieme di UID fornito.