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 Beispiel für ein Netzwerkdiagramm für ein Automobil:

Android Auto-Netzwerk

Abbildung 1: Android Auto-Netzwerk

In diesem Bild sehen Sie, wie Ihre 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 wird in diesem Dokument nicht behandelt.

Standard-Ethernet-Netzwerkeinstellungen 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>

In diesem Beispiel wird das config_ethernet_interfaces-Ressourcen-Overlay aus config.xml gezeigt.

Wichtige Punkte zum Code

  • eth1, eth2 und eth3 sind die Namen der zu konfigurierenden Netzwerkschnittstelle.
  • Die fortlaufenden Zahlen von 12, 13, 14, 15 stehen für die Aktivierung von Netzwerkfunktionen.
  • ip=, gateway= und dns werden verwendet, um die anfängliche IP-Adresse, das Gateway und den DNS für das Netzwerk festzulegen.

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 verwendet wird, um den Abschluss zu kommunizieren. Bei Erfolg wird der aktualisierte Netzwerkname zurückgegeben, bei einem Fehler EthernetNetworkManagementException.

Wenn eine Netzwerkschnittstelle aktiviert ist, werden die von EthernetManager.updateConfiguration() festgelegten Einstellungen verwendet. Wenn eine Konfiguration nicht von EthernetManager.updateConfiguration() festgelegt wurde, verwendet die Netzwerkschnittstelle das Ressourcen-Overlay config_ethernet_interfaces oder die Standardkonfiguration für das Ethernet-Netzwerk, falls kein Overlay verfügbar ist.

Rufen Sie EthernetManager.disableInterface() auf, um eine Netzwerkschnittstelle zu deaktivieren:

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 Netzwerkschnittstelle, die deaktiviert werden soll.
  • getMainExecutor() gibt den App-Kontext zurück.
  • OutcomeReceiver ist ein Callback, der verwendet wird, um den Abschluss zu kommunizieren. Bei Erfolg wird der aktualisierte Netzwerkname zurückgegeben, bei einem Fehler EthernetNetworkManagementException.

Netzwerkkonfiguration aktualisieren

So aktualisieren Sie Ethernet-Netzwerkkonfigurationen: 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 abruft und convertToUIDs() aufruft, um für Menschen lesbare Paketnamen in die eindeutige Linux-ID (UID) zu konvertieren. Normalerweise kennen Sie die UIDs für die zugehörigen Pakete nicht im Voraus. Wenn Sie EthernetManager.updateConfiguration() verwenden möchten, um den Zugriff auf eine Teilmenge von Apps zu beschränken, müssen Sie daher 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 im Konnektivitäts-Stack registriert ist, wird es gemäß der Konfiguration aktualisiert. Diese Konfiguration bleibt nach einem Neustart nicht bestehen.
  • getMainExecutor() gibt den Executor zurück, auf dem der Listener aufgerufen wird.
  • mCallback ist der Callback, der verwendet wird, um den Abschluss zu kommunizieren. Bei Erfolg wird der aktualisierte Netzwerkname zurückgegeben, bei einem Fehler EthernetNetworkManagementException.

updateConfiguration() kann Merkmale eines Netzwerks aktualisieren, die vom Android-Verbindungs-Stack als unveränderlich betrachtet werden. Das Netzwerk wird heruntergefahren, aktualisiert und wieder hochgefahren, 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 Teilmenge von OEM-Apps verwendet werden können.

Unter Android werden Apps in erster Linie anhand ihrer UID verfolgt. Der folgende Code aus UIDToPackageNameConverter.java zeigt, wie Sie eine Reihe von UIDs aus einem String mit Paketnamen abrufen:

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.

Der folgende Code in EthernetManagerTest.kt zeigt, wie Sie die Konfiguration der Netzwerkschnittstelle 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 angegebene Gruppe von UIDs zu beschränken.