Configurar redes Ethernet internas

O Android Auto OS 13 e versões mais recentes contêm recursos que permitem: configurar e gerenciar redes Ethernet. A Figura 1 mostra um exemplo de rede Diagrama de um automóvel:

Rede do Android Auto

Figura 1. Rede do Android Auto.

A figura mostra os métodos de chamada do seu app de rede de OEM na Classe EthernetManager para configurar e gerenciar redes Ethernet integradas (eth0.1, eth0.2 e eth0.3). O restante da Figura 1 está fora do escopo este documento.

Definir configurações padrão de rede Ethernet

Para definir as configurações de rede padrão, use o sobreposição 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>

Isso exemplo mostra a sobreposição de recurso config_ethernet_interfaces da config.xml.

Pontos principais sobre o código

  • eth1, eth2 e eth3 são os nomes da interface de rede que está sendo configurada.
  • Os números consecutivos de 12, 13, 14, 15 representam rede recursos que estão sendo ativados.
  • ip=, gateway= e dns são usados para definir o endereço IP inicial, o gateway e DNS para a rede.

Ativar ou desativar uma interface de rede

Para ativar uma interface de rede, chame 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);
    }
}

Pontos principais sobre o código

  • ifaceName é o nome da interface de rede a ser ativada.
  • getMainExecutor() retorna o contexto do app.
  • OutcomeReceiver é um callback usado para comunicar a conclusão retornando o nome da rede atualizado em caso de sucesso ou EthernetNetworkManagementException em erro.

Quando uma interface de rede é ativada, ela usa a configuração definida pelo EthernetManager.updateConfiguration(): Se uma configuração não tiver sido definida por EthernetManager.updateConfiguration(), a interface de rede usa o sobreposição de recursos config_ethernet_interfaces ou a rede Ethernet padrão se uma sobreposição não estiver disponível.

Para desativar uma interface de rede, chame 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);
    }
}

Pontos principais sobre o código

  • ifaceName é o nome da interface de rede a ser desativada.
  • getMainExecutor() retorna o contexto do app.
  • OutcomeReceiver é um callback usado para comunicar a conclusão retornando o nome da rede atualizado em caso de sucesso ou EthernetNetworkManagementException em erro.

Atualizar configuração de rede

Para atualizar de rede Ethernet, chame 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);

    }
}

Pontos principais sobre o código

  • getCapabilities() é um método auxiliar que busca a rede atual recursos e chama convertToUIDs() para converter nomes de pacotes legíveis para o identificador exclusivo (UID, na sigla em inglês) do Linux. Normalmente, não conhece os UIDs com antecedência para os pacotes associados. Portanto, se você quiser usar EthernetManager.updateConfiguration() para limitar o acesso a um subconjunto de apps, você precisam usar UIDs.
  • request é a configuração a ser usada para a rede interna. O solicitação pode conter novas configurações para a configuração do IP e da rede recursos. Se o estiver registrada na pilha de conectividade, ela é atualizada conforme a configuração do Terraform. Essa configuração não é mantida durante as reinicializações.
  • getMainExecutor() retorna o executor em que o listener é invocado.
  • mCallback é o callback usado para comunicar a conclusão retornando o nome da rede atualizado em caso de sucesso ou EthernetNetworkManagementException em erro.

updateConfiguration() pode atualizar as características de uma rede considerada imutável pela pilha de conectividade do Android. O rede é desativada, atualizada e restabelecida para esses imutáveis atributos a serem atualizados.

Restringir uma rede a um subconjunto de apps

Você pode usar EthernetManager#updateConfiguration para limitar o acesso a apenas um subconjunto de UIDs permitidos. Use este método para cobrir casos de uso em que obrigatórios, como redes veiculares internas que só podem ser usadas por um pequeno subconjunto de apps OEM.

O Android rastreia apps principalmente pelo UID. O código a seguir de UIDToPackageNameConverter.java mostra como receber uma série de UIDs de uma string de nomes de pacotes:

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;

Pontos principais sobre o código

  • O getApplicationInfoAsuser().uid é usado para recuperar o UID do nome do pacote.
  • uids é a matriz gerada de números inteiros.

O código a seguir no EthernetManagerTest.kt mostra como atualizar a configuração da interface de rede com UIDs dos apps têm permissão para usar a rede:

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

Em que:

  • allowUids é o conjunto de UIDs do app com permissão para usar a rede.
  • updateConfiguration() atualiza a configuração para restringir a rede aos o conjunto de UIDs fornecido.