配置内部以太网

Android Auto OS 13 及更高版本包含的功能允许您: 配置和管理以太网。图 1 显示了一个示例网络 汽车示意图:

Android Auto 网络

图 1. Android Auto 网络。

此图显示了 OEM 网络应用的调用方法 EthernetManager 类,用于配置和管理板载以太网网络 (eth0.1、eth0.2 和 eth0.3)。图 1 的其余部分不在 本文档。

设置默认的以太网网络设置

要设置默认网络设置,请使用 资源叠加层 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

有关代码的要点

  • eth1eth2eth3 是要配置的网络接口的名称。
  • 连续的数字 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 或默认以太网网络 配置。

要停用网络接口,请调用 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(在成功时) 错误。

更新网络配置

更新 以太网网络配置、调用 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() 可能会更新所考虑的网络的特征 不可变。通过 这些不可变特性会关闭、更新和恢复网络。 要更新的属性。

仅限部分应用使用网络

您可以使用 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 用于从 软件包名称
  • 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。