Android Auto OS 13 이상에는 이더넷 네트워크를 구성하고 관리할 수 있는 기능이 포함되어 있습니다. 그림 1은 자동차의 네트워크 다이어그램 예를 보여줍니다.
그림 1. Android Auto 네트워킹
이 그림은 EthernetManager 클래스에서 메서드를 호출하여 온보드 이더넷 네트워크(eth0.1, eth0.2, eth0.3)를 구성하고 관리하는 OEM 네트워킹 앱을 보여줍니다. 그림 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 집합으로 네트워크를 제한하도록 구성을 업데이트합니다.