Interne Ethernet-Netzwerke konfigurieren

Android Auto OS 13 und höher enthält Funktionen, mit denen Sie Ethernet-Netzwerke konfigurieren und verwalten können. Abbildung 1 zeigt ein Beispielnetzwerkdiagramm für ein Auto:

Android Auto-Netzwerk

Abbildung 1. Android Auto-Netzwerk

Diese Abbildung zeigt, wie die OEM-Netzwerk-App Methoden in der Klasse EthernetManager aufruft, um Onboard-Ethernet-Netzwerke (eth0.1, eth0.2 und eth0.3) zu konfigurieren und zu verwalten. Der Rest von Abbildung 1 fällt nicht in den Geltungsbereich dieses Dokuments.

Standardeinstellungen für Ethernet-Netzwerke festlegen

Verwenden Sie das Ressourcen-Overlay config_ethernet_interfaces, um Standardnetzwerkeinstellungen festzulegen:

<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>

Dieses Beispiel zeigt das config_ethernet_interfaces-Ressourcen-Overlay von config.xml.

Wichtige Punkte zum Code

  • eth1, eth2 und eth3 sind die Namen der konfigurierten Netzwerkschnittstelle.
  • Die aufeinanderfolgenden Zahlen von 12, 13, 14, 15 stehen für aktivierte Netzwerkfunktionen.
  • Mit ip=, gateway= und dns werden die initiale IP-Adresse, das Gateway und das DNS für das Netzwerk festgelegt.

Netzwerkschnittstelle aktivieren oder deaktivieren

Rufen Sie EthernetManager.enableInterface() auf, um eine Netzwerkschnittstelle zu aktivieren:

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);
    }
}

Wichtige Punkte zum Code

  • ifaceName ist der Name der zu aktivierenden Netzwerkschnittstelle.
  • getMainExecutor() gibt den App-Kontext zurück.
  • OutcomeReceiver ist ein Callback, der den Abschluss anzeigt. Bei Erfolg wird der aktualisierte Netzwerkname zurückgegeben, bei Fehler EthernetNetworkManagementException.

Wenn eine Netzwerkschnittstelle aktiviert ist, wird die von EthernetManager.updateConfiguration() festgelegte Konfiguration verwendet. Wenn keine Konfiguration von EthernetManager.updateConfiguration() festgelegt wurde, verwendet die Netzwerkschnittstelle das Ressourcen-Overlay config_ethernet_interfaces oder die Standard-Ethernet-Netzwerkkonfiguration, falls kein Overlay verfügbar ist.

So deaktivieren Sie eine Netzwerkschnittstelle: 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);
    }
}

Wichtige Punkte zum Code

  • ifaceName ist der Name der zu deaktivierenden Netzwerkschnittstelle.
  • getMainExecutor() gibt den App-Kontext zurück.
  • OutcomeReceiver ist ein Callback, der den Abschluss anzeigt. Bei Erfolg wird der aktualisierte Netzwerkname zurückgegeben, bei Fehler EthernetNetworkManagementException.

Netzwerkkonfiguration aktualisieren

Wenn Sie Ethernet-Netzwerkkonfigurationen aktualisieren möchten, rufen Sie EthernetManager.updateConfiguration() auf:

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);

    }
}

Wichtige Punkte zum Code

  • getCapabilities() ist eine Hilfsmethode, die die aktuellen Netzwerkfunktionen abrufen und convertToUIDs() aufrufen, um visuell lesbare Paketnamen in eine eindeutige Linux-Kennung (UID) umzuwandeln. Normalerweise kennen Sie die UIDs für die zugehörigen Pakete nicht im Voraus. Wenn Sie also EthernetManager.updateConfiguration() verwenden möchten, um den Zugriff auf eine Teilmenge von Apps einzuschränken, müssen Sie deren UIDs verwenden.
  • request ist die Konfiguration, die für das interne Netzwerk verwendet werden soll. Die Anfrage kann neue Einstellungen für die IP-Konfiguration und die Netzwerkfunktionen enthalten. Wenn das Netzwerk beim Konnektivitätsstack registriert ist, wird es gemäß der Konfiguration aktualisiert. Diese Konfiguration bleibt nach einem Neustart nicht bestehen.
  • getMainExecutor() gibt den Executor zurück, über den der Listener aufgerufen wird.
  • mCallback ist der Callback, mit dem der Abschluss mitgeteilt wird. Bei Erfolg wird der aktualisierte Netzwerkname zurückgegeben, bei Fehlern EthernetNetworkManagementException.

updateConfiguration() kann Eigenschaften eines Netzwerks aktualisieren, die vom Android-Netzwerkstack als unveränderlich betrachtet werden. Das Netzwerk wird heruntergefahren, aktualisiert und wieder gestartet, damit diese unveränderlichen Attribute aktualisiert werden können.

Netzwerk auf eine Teilmenge von Apps beschränken

Mit EthernetManager#updateConfiguration können Sie den Zugriff auf eine Teilmenge der zulässigen UIDs beschränken. Verwenden Sie diese Methode für Anwendungsfälle, in denen dies erforderlich ist, z. B. für interne Fahrzeugnetzwerke, die nur von einer kleinen Gruppe von OEM-Apps verwendet werden können.

Android erfasst Apps hauptsächlich anhand ihrer UID. Im folgenden Code aus UIDToPackageNameConverter.java wird gezeigt, wie eine Reihe von UIDs aus einem String mit Paketnamen abgerufen wird:

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;

Wichtige Punkte zum Code

  • getApplicationInfoAsuser().uid wird verwendet, um die UID aus dem Paketnamen abzurufen.
  • uids ist das generierte Array mit Ganzzahlen.

Im folgenden Code in EthernetManagerTest.kt wird gezeigt, wie Sie die Netzwerkschnittstellenkonfiguration mit den UIDs der Apps aktualisieren, die das Netzwerk verwenden dürfen:

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

Wichtige Punkte zum Code

  • allowUids ist die Gruppe der App-UIDs, die das Netzwerk verwenden dürfen.
  • updateConfiguration() aktualisiert die Konfiguration, um das Netzwerk auf die angegebenen UIDs zu beschränken.