Configura redes Ethernet internas

Android Auto OS 13 y versiones posteriores contienen funciones que te permiten configurar y administrar redes Ethernet. En la Figura 1, se muestra un diagrama de red de ejemplo para un automóvil:

Redes de Android Auto

Figura 1: Redes de Android Auto

En esta figura, se muestra tu app de redes OEM que llama a métodos en la clase EthernetManager para configurar y administrar redes Ethernet integradas (eth0.1, eth0.2 y eth0.3). El resto de la Figura 1 está fuera del alcance de este documento.

Establece la configuración de red Ethernet predeterminada

Para establecer la configuración de red predeterminada, usa la superposición de recursos 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>

En este ejemplo, se muestra la superposición de recursos config_ethernet_interfaces de config.xml.

Puntos clave sobre el código

  • eth1, eth2 y eth3 son los nombres de la interfaz de red que se está configurando.
  • Los números consecutivos de 12, 13, 14, 15 representan las capacidades de red que se habilitan.
  • ip=, gateway= y dns se usan para establecer la dirección IP, la puerta de enlace y el DNS iniciales de la red.

Habilita o inhabilita una interfaz de red

Para habilitar una interfaz de red, llama a 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);
    }
}

Puntos clave sobre el código

  • ifaceName es el nombre de la interfaz de red que se habilitará.
  • getMainExecutor() muestra el contexto de la app.
  • OutcomeReceiver es una devolución de llamada que se usa para comunicar la finalización y muestra el nombre de red actualizado si la operación se realiza correctamente o EthernetNetworkManagementException si se produce un error.

Cuando se habilita una interfaz de red, usa la configuración establecida por EthernetManager.updateConfiguration(). Si EthernetManager.updateConfiguration() no estableció una configuración, la interfaz de red usa la superposición de recursos config_ethernet_interfaces o la configuración de red Ethernet predeterminada si no hay una superposición disponible.

Para inhabilitar una interfaz de red, llama a 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);
    }
}

Puntos clave sobre el código

  • ifaceName es el nombre de la interfaz de red que se inhabilitará.
  • getMainExecutor() muestra el contexto de la app.
  • OutcomeReceiver es una devolución de llamada que se usa para comunicar la finalización y muestra el nombre de red actualizado si la operación se realiza correctamente o EthernetNetworkManagementException si se produce un error.

Actualiza la configuración de red

Para actualizar las configuraciones de red Ethernet, llama a 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);

    }
}

Puntos clave sobre el código

  • getCapabilities() es un método auxiliar que obtiene las capacidades de red actuales y llama a convertToUIDs() para convertir nombres de paquetes legibles por humanos en un identificador único (UID) de Linux. Por lo general, no conoces los UID de antemano para sus paquetes asociados. Por lo tanto, si deseas usar EthernetManager.updateConfiguration() para limitar el acceso a un subconjunto de apps, debes usar sus UID.
  • request es la configuración que se usará para la red interna. La solicitud puede contener una configuración nueva para la configuración de IP y las capacidades de red. Si la red está registrada en la pila de conectividad, se actualiza según la configuración. Esta configuración no persiste durante los reinicios.
  • getMainExecutor() muestra el ejecutor en el que se invoca el objeto de escucha.
  • mCallback es la devolución de llamada que se usa para comunicar la finalización y muestra el nombre de red actualizado si la operación se realiza correctamente o EthernetNetworkManagementException si se produce un error.

updateConfiguration() puede actualizar las características de una red que la pila de conectividad de Android considera inmutable. La red se desactiva, se actualiza y se vuelve a activar para que se actualicen estos atributos inmutables.

Restringe una red a un subconjunto de apps

Puedes usar EthernetManager#updateConfiguration para limitar el acceso solo a un subconjunto de UID permitidos. Usa este método para cubrir casos de uso en los que sea necesario, como para redes vehiculares internas que solo puede usar un pequeño subconjunto de apps OEM.

Android realiza un seguimiento de las apps principalmente por su UID. En el siguiente código de UIDToPackageNameConverter.java , se muestra cómo obtener una serie de UID a partir de una cadena de nombres de paquetes:

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;

Puntos clave sobre el código

  • getApplicationInfoAsuser().uid se usa para recuperar el UID del nombre del paquete.
  • uids es el array de números enteros generado.

En el siguiente código de EthernetManagerTest.kt , se muestra cómo actualizar la configuración de la interfaz de red con un UID de las apps que pueden usar la red:

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

Puntos clave sobre el código

  • allowUids es el conjunto de UID de apps que pueden usar la red.
  • updateConfiguration() actualiza la configuración para restringir la red al conjunto de UID proporcionado.