Configurer des réseaux Ethernet internes

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

Mise en réseau Android Auto

Figure 1 : Mise en réseau Android Auto

Cette figure montre comment votre application de mise en réseau OEM appelle des méthodes dans la classe EthernetManager pour configurer et gérer les réseaux Ethernet intégrés (eth0.1, eth0.2 et eth0.3). Le reste de la figure 1 n'entre pas dans le champ d'application 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 la 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 de l'interface 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 initiales du 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 l'achèvement en renvoyant le nom de réseau mis à jour en cas de réussite ou EthernetNetworkManagementException en cas d'erreur.

Lorsqu'une interface réseau est activée, elle utilise la configuration définie par EthernetManager.updateConfiguration(). Si aucune configuration n'a été définie par EthernetManager.updateConfiguration(), 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 l'achèvement en renvoyant le nom de réseau mis à jour en cas de réussite ou EthernetNetworkManagementException en cas d'erreur.

Mettre à jour la configuration réseau

Pour mettre à jour les configurations de 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 fonctionnalités réseau actuelles et appelle convertToUIDs() pour convertir les noms de paquets lisibles par l'homme en identifiant unique (UID) Linux. En règle générale, vous ne connaissez pas à l'avance les UID des 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 est la configuration à utiliser pour le réseau interne. La requête peut contenir de nouveaux paramètres pour la configuration IP et les fonctionnalité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 l'achèvement en renvoyant le nom de réseau mis à jour en cas de réussite 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.

Limiter 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 automobiles internes utilisables uniquement par un petit sous-ensemble d'applications OEM.

Android suit principalement les applications via 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.