Настройка внутренних сетей Ethernet

Android Auto OS 13 и выше содержит функции, позволяющие настраивать и управлять сетями Ethernet. На рисунке 1 показан пример сетевой схемы для автомобиля:

Сетевое взаимодействие Android Auto

Рисунок 1. Сетевое взаимодействие Android Auto.

На этом рисунке показано, как ваше сетевое приложение OEM вызывает методы в классе EthernetManager для настройки и управления встроенными сетями Ethernet (eth0.1, eth0.2 и eth0.3). Остальная часть рисунка 1 выходит за рамки этого документа.

Установить настройки сети Ethernet по умолчанию

Чтобы задать параметры сети по умолчанию, используйте наложение ресурсов 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>

В этом примере показано наложение ресурсов config_ethernet_interfaces из config.xml .

Ключевые моменты кодекса

  • eth1 , eth2 и eth3 — имена настраиваемых сетевых интерфейсов.
  • Последовательные числа 12, 13, 14, 15 представляют собой включаемые сетевые возможности .
  • ip= , gateway= и dns используются для установки начального IP-адреса, шлюза и DNS для сети.

Включить или отключить сетевой интерфейс

Чтобы включить сетевой интерфейс, вызовите 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);
    }
}

Ключевые моменты кодекса

  • ifaceName — имя сетевого интерфейса, который необходимо включить.
  • getMainExecutor() возвращает контекст приложения.
  • OutcomeReceiver — это обратный вызов, используемый для сообщения о завершении, возвращающий обновленное имя сети в случае успеха или EthernetNetworkManagementException в случае ошибки.

Когда сетевой интерфейс включен, он использует конфигурацию, установленную EthernetManager.updateConfiguration() . Если конфигурация не была установлена EthernetManager.updateConfiguration() , сетевой интерфейс использует наложение ресурсов config_ethernet_interfaces или конфигурацию сети Ethernet по умолчанию, если наложение недоступно.

Чтобы отключить сетевой интерфейс, вызовите 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);
    }
}

Ключевые моменты кодекса

  • ifaceName — имя сетевого интерфейса, который необходимо отключить.
  • getMainExecutor() возвращает контекст приложения.
  • OutcomeReceiver — это обратный вызов, используемый для сообщения о завершении, возвращающий обновленное имя сети в случае успеха или EthernetNetworkManagementException в случае ошибки.

Обновить конфигурацию сети

Чтобы обновить конфигурации сети Ethernet, вызовите 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);

    }
}

Ключевые моменты кодекса

  • getCapabilities() — это вспомогательный метод, который получает текущие сетевые возможности и вызывает convertToUIDs() для преобразования понятных человеку имен пакетов в уникальный идентификатор Linux (UID) . Обычно вы заранее не знаете UID для связанных с ними пакетов. Поэтому, если вы хотите использовать EthernetManager.updateConfiguration() для ограничения доступа к подмножеству приложений, вам нужно использовать их UID.
  • request — это конфигурация, которая будет использоваться для внутренней сети. Запрос может содержать новые настройки для конфигурации IP и сетевых возможностей. Если сеть зарегистрирована в стеке подключений, она обновляется в соответствии с конфигурацией. Эта конфигурация не сохраняется при перезагрузках.
  • getMainExecutor() возвращает исполнитель, для которого вызывается прослушиватель.
  • mCallback — это обратный вызов, используемый для сообщения о завершении, возвращающий обновленное имя сети в случае успеха или EthernetNetworkManagementException в случае ошибки.

updateConfiguration() может обновить характеристики сети, которые стек Android Connectivity считает неизменяемыми. Сеть останавливается, обновляется и снова включается для обновления этих неизменяемых атрибутов.

Ограничить сеть подмножеством приложений

Вы можете использовать EthernetManager#updateConfiguration чтобы ограничить доступ только подмножеством разрешенных UID. Используйте этот метод для покрытия случаев использования, где это требуется, например, для внутренних транспортных сетей, которые могут использоваться только небольшим подмножеством приложений OEM.

Android в первую очередь отслеживает приложения по их UID. Следующий код из UIDToPackageNameConverter.java показывает, как получить ряд UID из строки имен пакетов:

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;

Ключевые моменты кодекса

  • getApplicationInfoAsuser().uid используется для извлечения UID из имени пакета.
  • uids — это сгенерированный массив целых чисел.

Следующий код в EthernetManagerTest.kt показывает, как обновить конфигурацию сетевого интерфейса с помощью UID приложений, которым разрешено использовать сеть:

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

Ключевые моменты кодекса

  • allowUids — это набор UID приложений, которым разрешено использовать сеть.
  • updateConfiguration() обновляет конфигурацию, ограничивая сеть предоставленным набором UID.