Configurer des réseaux Ethernet internes

Android Automotive OS 13 et versions ultérieures contiennent des fonctionnalités qui vous permettent de configurer et de gérer les réseaux Ethernet. La figure 1 montre un exemple de schéma de réseau pour une automobile :

Mise en réseau d'Android Auto

Figure 1 : Mise en réseau Android Auto.

Cette figure montre votre application réseau OEM appelant des méthodes dans la classe EthernetManager pour configurer et gérer les réseaux Ethernet embarqués (eth0.1, eth0.2 et eth0.3). Le reste de la figure 1 ne relève pas de ce document.

Définir les paramètres réseau Ethernet par défaut

Pour définir les paramètres réseau par défaut, utilisez le fichier de superposition de ressources 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>

Cet exemple montre la superposition de ressources config_ethernet_interfaces à partir de config.xml.

Points clés concernant le code

  • eth1, eth2 et eth3 sont les noms des interfaces réseau en cours de configuration.
  • Les nombres consécutifs de 12, 13, 14, 15 représentent les fonctionnalités réseau activées.
  • ip=, gateway= et dns permettent de définir l'adresse IP, la passerelle et le DNS initiaux pour le réseau.

Activer ou désactiver une interface réseau

Pour activer une interface réseau, appelez 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);
    }
}

Points clés concernant le code

  • ifaceName correspond au nom de l'interface réseau à activer.
  • getMainExecutor() renvoie le contexte de l'application.
  • OutcomeReceiver est un rappel utilisé pour communiquer la fin de l'opération, en renvoyant le nom du réseau mis à jour en cas de succès ou EthernetNetworkManagementException en cas d'erreur.

Lorsqu'une interface réseau est activée, elle utilise la configuration définie par EthernetManager.updateConfiguration(). Si EthernetManager.updateConfiguration() n'a pas défini de configuration, l'interface réseau utilise la superposition de ressources config_ethernet_interfaces ou la configuration réseau Ethernet par défaut si aucune superposition n'est disponible.

Pour désactiver une interface réseau, appelez 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);
    }
}

Points clés concernant le code

  • ifaceName correspond au nom de l'interface réseau à désactiver.
  • getMainExecutor() renvoie le contexte de l'application.
  • OutcomeReceiver est un rappel utilisé pour communiquer la fin de l'opération, en renvoyant le nom du réseau mis à jour en cas de succès ou EthernetNetworkManagementException en cas d'erreur.

Mettre à jour la configuration réseau

Pour mettre à jour les configurations du réseau Ethernet, appelez 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);

    }
}

Points clés concernant le code

  • getCapabilities() est une méthode d'assistance qui obtient les capacités réseau actuelles et appelle convertToUIDs() pour convertir les noms de packages lisibles par l'homme en identifiant unique (UID) Linux. En général, vous ne connaissez pas à l'avance les UID de leurs packages associés. Par conséquent, si vous souhaitez utiliser EthernetManager.updateConfiguration() pour limiter l'accès à un sous-ensemble d'applications, vous devez utiliser leurs UID.
  • request correspond à la configuration à utiliser pour le réseau interne. La requête peut contenir de nouveaux paramètres pour la configuration IP et les capacités réseau. Si le réseau est enregistré auprès de la pile de connectivité, il est mis à jour conformément à la configuration. Cette configuration ne persiste pas lors des redémarrages.
  • getMainExecutor() renvoie l'exécuteur sur lequel l'écouteur est appelé.
  • mCallback est le rappel utilisé pour communiquer la fin de l'opération, en renvoyant le nom du réseau mis à jour en cas de succès ou EthernetNetworkManagementException en cas d'erreur.

updateConfiguration() peut mettre à jour les caractéristiques d'un réseau considéré comme immuable par la pile de connectivité Android. Le réseau est mis hors service, mis à jour et remis en service pour que ces attributs immuables soient mis à jour.

Restreindre un réseau à un sous-ensemble d'applications

Vous pouvez utiliser EthernetManager#updateConfiguration pour limiter l'accès à un sous-ensemble d'UID autorisés. Utilisez cette méthode pour couvrir les cas d'utilisation où cela est nécessaire, par exemple pour les réseaux de véhicules internes utilisables uniquement par un petit sous-ensemble d'applications OEM.

Android suit principalement les applications par leur UID. Le code suivant de UIDToPackageNameConverter.java montre comment obtenir une série d'UID à partir d'une chaîne de noms de packages :

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;

Points clés concernant le code

  • getApplicationInfoAsuser().uid permet de récupérer l'UID à partir du nom du package.
  • uids est le tableau d'entiers généré.

Le code suivant dans EthernetManagerTest.kt montre comment mettre à jour la configuration de votre interface réseau avec les UID des applications autorisées à utiliser le réseau :

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

Points clés concernant le code

  • allowUids est l'ensemble des UID d'application autorisés à utiliser le réseau.
  • updateConfiguration() met à jour la configuration pour limiter le réseau à l'ensemble d'UID fourni.