Android Auto OS 13 及更高版本包含一些可让您配置和管理以太网的功能。图 1 显示了汽车的一个网络图示例:
图 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.xml
的 config_ethernet_interfaces
资源叠加层。
代码要点
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
,如果没有叠加层,则会使用默认以太网配置。
如需停用网络接口,请调用 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()
可能会更新 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 可访问。