Настройка внутренних сетей 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. Для обновления этих неизменяемых атрибутов сеть отключается, обновляется и снова включается.

Ограничить доступ к сети определенным набором приложений.

Вы можете использовать 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.