AIDL für HALs

Mit Android 11 wird die Möglichkeit eingeführt, AIDL für HALs in Android zu verwenden. Dadurch können Teile von Android ohne HIDL implementiert werden. HALs sollten nach Möglichkeit ausschließlich AIDL verwenden (wenn Upstream-HALs HIDL verwenden, muss HIDL verwendet werden).

HALs, die AIDL für die Kommunikation zwischen Framework-Komponenten wie system.img und Hardwarekomponenten wie vendor.img verwenden, müssen stabiles AIDL verwenden. Für die Kommunikation innerhalb einer Partition, z. B. von einem HAL zu einem anderen, gibt es jedoch keine Einschränkungen hinsichtlich des zu verwendenden IPC-Mechanismus.

Ziel

AIDL gibt es schon länger als HIDL und es wird an vielen anderen Stellen verwendet, z. B. zwischen Android-Framework-Komponenten oder in Apps. Da AIDL jetzt Stabilität unterstützt, kann ein gesamter Stack mit einer einzigen IPC-Laufzeit implementiert werden. AIDL hat auch ein besseres Versionsverwaltungssystem als HIDL. Hier sind einige Vorteile von AIDL:

  • Wenn Sie nur eine IPC-Sprache verwenden, müssen Sie nur eine Sache lernen, debuggen, optimieren und schützen.
  • AIDL unterstützt die In-Place-Versionsverwaltung für die Eigentümer einer Schnittstelle:
    • Inhaber können Methoden am Ende von Schnittstellen oder Felder zu Parcelables hinzufügen. Das bedeutet, dass sich Code im Laufe der Jahre leichter versionieren lässt und die Kosten im Jahresvergleich geringer sind, da Typen direkt geändert werden können und für jede Schnittstellenversion keine zusätzlichen Bibliotheken erforderlich sind.
    • Erweiterungsschnittstellen können zur Laufzeit und nicht im Typsystem angehängt werden. Daher müssen nachgelagerte Erweiterungen nicht auf neuere Versionen von Schnittstellen umgestellt werden.
  • Eine vorhandene AIDL-Schnittstelle kann direkt verwendet werden, wenn ihr Eigentümer sie stabilisiert. Bisher musste eine vollständige Kopie der Schnittstelle in HIDL erstellt werden.

Mit der AIDL-Laufzeit erstellen

AIDL hat drei verschiedene Back-Ends: Java, NDK und CPP. Wenn Sie stabiles AIDL verwenden möchten, verwenden Sie immer die Systemkopie von libbinder unter system/lib*/libbinder.so und kommunizieren Sie über /dev/binder. Für Code im vendor-Image bedeutet das, dass libbinder (aus dem VNDK) nicht verwendet werden kann, da diese Bibliothek eine instabile C++-API und instabile interne Komponenten hat. Stattdessen muss nativer Anbietercode das NDK-Backend von AIDL verwenden, mit libbinder_ndk (das von System libbinder.so unterstützt wird) und mit den NDK-Bibliotheken verknüpft werden, die durch aidl_interface-Einträge erstellt wurden. Die genauen Modulnamen finden Sie unter Regeln für die Modulbenennung.

AIDL-HAL-Schnittstelle schreiben

Damit eine AIDL-Schnittstelle zwischen System und Anbieter verwendet werden kann, sind zwei Änderungen erforderlich:

  • Jede Typdefinition muss mit @VintfStability annotiert werden.
  • Die aidl_interface-Deklaration muss stability: "vintf", enthalten.

Nur der Eigentümer einer Schnittstelle kann diese Änderungen vornehmen.

Wenn Sie diese Änderungen vornehmen, muss die Schnittstelle im VINTF-Manifest enthalten sein, damit sie funktioniert. Testen Sie dies (und zugehörige Anforderungen, z. B. die Überprüfung, ob veröffentlichte Schnittstellen eingefroren sind) mit dem VTS-Test (Vendor Test Suite) vts_treble_vintf_vendor_test. Sie können eine @VintfStability-Schnittstelle ohne diese Anforderungen verwenden, indem Sie entweder AIBinder_forceDowngradeToLocalStability im NDK-Backend, android::Stability::forceDowngradeToLocalStability im C++-Backend oder android.os.Binder#forceDowngradeToSystemStability im Java-Backend für ein Binder-Objekt aufrufen, bevor es an einen anderen Prozess gesendet wird.

Deaktivieren Sie außerdem das CPP-Backend, um die Code-Übertragbarkeit zu maximieren und potenzielle Probleme wie unnötige zusätzliche Bibliotheken zu vermeiden.

Der Code zeigt, wie das CPP-Backend deaktiviert wird:

    aidl_interface: {
        ...
        backend: {
            cpp: {
                enabled: false,
            },
        },
    }

AIDL-HAL-Schnittstellen finden

Stabile AIDL-Schnittstellen für HALs in AOSP befinden sich in aidl-Ordnern in denselben Basisverzeichnissen wie HIDL-Schnittstellen:

  • hardware/interfaces bezieht sich auf Schnittstellen, die in der Regel von der Hardware bereitgestellt werden.
  • frameworks/hardware/interfaces ist für allgemeine Schnittstellen vorgesehen, die für Hardware bereitgestellt werden.
  • system/hardware/interfaces ist für Low-Level-Schnittstellen, die für Hardware bereitgestellt werden.

Legen Sie Erweiterungsschnittstellen in anderen hardware/interfaces-Unterverzeichnissen in vendor oder hardware ab.

Erweiterungsschnittstellen

Mit jedem Release gibt es eine Reihe offizieller AOSP-Schnittstellen. Wenn Android-Partner diesen Schnittstellen Funktionen hinzufügen möchten, sollten sie sie nicht direkt ändern, da ihre Android-Laufzeit sonst nicht mit der AOSP-Android-Laufzeit kompatibel ist. Vermeiden Sie Änderungen an diesen Schnittstellen, damit das GSI-Image weiterhin funktioniert.

Erweiterungen können sich auf zwei verschiedene Arten registrieren:

Wenn eine Erweiterung registriert ist und anbieterspezifische Komponenten (d. h. keine Upstream-AOSP-Komponenten) die Schnittstelle verwenden, sind keine Merge-Konflikte möglich. Wenn jedoch Downstream-Änderungen an Upstream-AOSP-Komponenten vorgenommen werden, können Merge-Konflikte auftreten. In diesem Fall werden die folgenden Strategien empfohlen:

  • Die Schnittstellenerweiterungen im nächsten Release in AOSP einfügen.
  • Upstream-Schnittstellenerweiterungen, die in der nächsten Version mehr Flexibilität ermöglichen (ohne Merge-Konflikte).

Parcelable-Objekte für Erweiterungen: ParcelableHolder

ParcelableHolder ist eine Instanz der Parcelable-Schnittstelle, die eine weitere Instanz von Parcelable enthalten kann.

Der Hauptanwendungsfall von ParcelableHolder besteht darin, Parcelable erweiterbar zu machen. Angenommen, Gerätehersteller möchten eine in AOSP definierte Parcelable, AospDefinedParcelable, erweitern, um ihre Mehrwertfunktionen einzubinden.

Verwenden Sie die ParcelableHolder-Schnittstelle, um Parcelable mit Ihren Mehrwertfunktionen zu erweitern. Die Schnittstelle ParcelableHolder enthält eine Instanz von Parcelable. Wenn Sie versuchen, Felder direkt zu Parcelable hinzuzufügen, tritt ein Fehler auf:

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

Wie im vorherigen Code zu sehen ist, ist diese Vorgehensweise problematisch, da die vom Gerätehersteller hinzugefügten Felder möglicherweise in Konflikt geraten, wenn Parcelable in den nächsten Android-Versionen überarbeitet wird.

Mit ParcelableHolder kann der Inhaber eines Parcelable einen Erweiterungspunkt in einer Instanz von Parcelable definieren:

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

Anschließend können die Geräteimplementierer ihre eigene Parcelable-Instanz für ihre Erweiterung definieren:

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

Die neue Parcelable-Instanz kann mit dem Feld ParcelableHolder an die ursprüngliche Parcelable-Instanz angehängt werden:


// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;

ap.extension.setParcelable(op);

...

OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);

// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();

ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);

...

std::shared_ptr<OemDefinedParcelable> op_ptr;

ap.extension.getParcelable(&op_ptr);

// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);

...

std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);

// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });

ap.extension.set_parcelable(Rc::clone(&op));

...

let op = ap.extension.get_parcelable::<OemDefinedParcelable>();

AIDL-HAL-Serverinstanznamen

AIDL-HAL-Dienste haben üblicherweise einen Instanznamen im Format $package.$type/$instance. Eine Instanz der Vibrator-HAL wird beispielsweise als android.hardware.vibrator.IVibrator/default registriert.

AIDL-HAL-Server schreiben

@VintfStability AIDL-Server müssen im VINTF-Manifest deklariert werden. Beispiel:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

Andernfalls sollten sie einen AIDL-Dienst wie gewohnt registrieren. Beim Ausführen von VTS-Tests wird erwartet, dass alle deklarierten AIDL-HALs verfügbar sind.

AIDL-Client schreiben

AIDL-Clients müssen sich in der Kompatibilitätsmatrix deklarieren, z. B.:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

Vorhandenes HAL von HIDL zu AIDL konvertieren

Verwenden Sie das hidl2aidl-Tool, um eine HIDL-Schnittstelle in AIDL zu konvertieren.

hidl2aidl-Funktionen:

  • Erstellen Sie AIDL-Dateien (.aidl) basierend auf den HAL-Dateien (.hal) für das angegebene Paket.
  • Erstellen Sie Build-Regeln für das neu erstellte AIDL-Paket mit allen aktivierten Backends.
  • Erstellen Sie in den Java-, CPP- und NDK-Back-Ends Übersetzungsfunktionen, um von den HIDL-Typen zu den AIDL-Typen zu übersetzen.
  • Erstellen Sie Build-Regeln für Übersetzungsbibliotheken mit den erforderlichen Abhängigkeiten.
  • Erstellen Sie statische Zusicherungen, um sicherzustellen, dass HIDL- und AIDL-Enumeratoren in den CPP- und NDK-Backends dieselben Werte haben.

So konvertieren Sie ein Paket von HAL-Dateien in AIDL-Dateien:

  1. Erstellen Sie das Tool unter system/tools/hidl/hidl2aidl.

    Wenn Sie dieses Tool aus dem neuesten Quellcode erstellen, erhalten Sie die umfassendste Erfahrung. Mit der neuesten Version können Sie Schnittstellen in älteren Branches aus früheren Releases konvertieren:

    m hidl2aidl
  2. Führen Sie das Tool mit einem Ausgabeverzeichnis und dem zu konvertierenden Paket aus.

    Optional können Sie mit dem Argument -l den Inhalt einer neuen Lizenzdatei am Anfang aller generierten Dateien einfügen. Achten Sie darauf, dass Sie die richtige Lizenz und das richtige Datum verwenden:

    hidl2aidl -o <output directory> -l <file with license> <package>

    Beispiel:

    hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
  3. Sehen Sie sich die generierten Dateien an und beheben Sie alle Probleme bei der Konvertierung:

    • conversion.log enthält alle unbehandelten Probleme, die zuerst behoben werden müssen.
    • Die generierten AIDL-Dateien enthalten möglicherweise Warnungen und Vorschläge, die Maßnahmen erfordern. Diese Kommentare beginnen mit //.
    • Bereinigen Sie das Paket und nehmen Sie Verbesserungen vor.
    • Sehen Sie sich die Anmerkung @JavaDerive an, um herauszufinden, welche Funktionen möglicherweise erforderlich sind, z. B. toString oder equals.
  4. Nur die erforderlichen Ziele erstellen:

    • Deaktivieren Sie Back-Ends, die nicht verwendet werden. Bevorzugen Sie das NDK-Backend gegenüber dem CPP-Backend. Weitere Informationen finden Sie unter Für die AIDL-Laufzeitumgebung erstellen.
    • Entfernen Sie Übersetzungsbibliotheken oder generierten Code, der nicht verwendet wird.
  5. Weitere Informationen finden Sie unter Wichtige Unterschiede zwischen AIDL und HIDL:

    • Die Verwendung der integrierten Status und Ausnahmen von AIDL verbessert in der Regel die Schnittstelle und macht einen weiteren schnittstellenspezifischen Statustyp überflüssig.
    • AIDL-Schnittstellenargumente in Methoden sind nicht standardmäßig @nullable wie in HIDL.

SEPolicy für AIDL-HALs

Ein AIDL-Diensttyp, der für Vendorencode sichtbar ist, muss das Attribut hal_service_type haben. Andernfalls ist die sepolicy-Konfiguration dieselbe wie bei jedem anderen AIDL-Dienst (obwohl es spezielle Attribute für HALs gibt). Hier ist ein Beispiel für die Definition eines HAL-Dienstkontexts:

    type hal_foo_service, service_manager_type, hal_service_type;

Für die meisten von der Plattform definierten Dienste wird bereits ein Dienstkontext mit dem richtigen Typ hinzugefügt (z. B. ist android.hardware.foo.IFoo/default bereits als hal_foo_service gekennzeichnet). Wenn ein Framework-Client jedoch mehrere Instanznamen unterstützt, müssen zusätzliche Instanznamen in gerätespezifischen service_contexts-Dateien hinzugefügt werden:

    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0

Wenn Sie einen neuen HAL-Typ erstellen, müssen Sie HAL-Attribute hinzufügen. Ein bestimmtes HAL-Attribut kann mehreren Diensttypen zugeordnet sein, von denen jeder mehrere Instanzen haben kann (wie oben beschrieben). Für ein HAL, foo, gibt es hal_attribute(foo). Mit diesem Makro werden die Attribute hal_foo_client und hal_foo_server definiert. Für eine bestimmte Domain verknüpfen die Makros hal_client_domain und hal_server_domain eine Domain mit einem bestimmten HAL-Attribut. Wenn der Systemserver beispielsweise ein Client dieses HAL ist, entspricht das der Richtlinie hal_client_domain(system_server, hal_foo). Ein HAL-Server enthält ebenfalls hal_server_domain(my_hal_domain, hal_foo).

Erstellen Sie in der Regel für ein bestimmtes HAL-Attribut auch eine Domain wie hal_foo_default als Referenz oder Beispiel-HAL. Einige Geräte verwenden diese Domains jedoch für ihre eigenen Server. Die Unterscheidung zwischen Domains für mehrere Server ist nur dann wichtig, wenn es mehrere Server gibt, die dieselbe Schnittstelle bereitstellen und in ihren Implementierungen unterschiedliche Berechtigungssätze benötigen. In allen diesen Makros ist hal_foo kein sepolicy-Objekt. Stattdessen wird dieses Token von diesen Makros verwendet, um auf die Gruppe von Attributen zu verweisen, die einem Client-Server-Paar zugeordnet sind.

Bisher sind hal_foo_service und hal_foo (das Attributpaar aus hal_attribute(foo)) jedoch nicht verknüpft. Ein HAL-Attribut wird AIDL-HAL-Diensten mit dem Makro hal_attribute_service zugeordnet (HIDL-HALs verwenden das Makro hal_attribute_hwservice), z. B. hal_attribute_service(hal_foo, hal_foo_service). Das bedeutet, dass hal_foo_client-Prozesse das HAL abrufen und hal_foo_server-Prozesse das HAL registrieren können. Die Durchsetzung dieser Registrierungsregeln erfolgt durch den Kontextmanager (servicemanager).

Dienstnamen entsprechen möglicherweise nicht immer HAL-Attributen, z. B. hal_attribute_service(hal_foo, hal_foo2_service). Da dies im Allgemeinen bedeutet, dass die Dienste immer zusammen verwendet werden, können Sie hal_foo2_service entfernen und hal_foo_service für alle Dienstkontexte verwenden. Wenn HALs mehrere hal_attribute_service-Instanzen festlegen, liegt das daran, dass der ursprüngliche HAL-Attributname nicht allgemein genug ist und nicht geändert werden kann.

All dies zusammengeführt ergibt ein Beispiel-HAL, das so aussieht:

    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)

    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type

    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)

    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0

    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)

    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)

Angehängte Erweiterungsschnittstellen

Eine Erweiterung kann an jede Binder-Schnittstelle angehängt werden, unabhängig davon, ob es sich um eine Schnittstelle der obersten Ebene handelt, die direkt beim Dienstmanager registriert ist, oder um eine untergeordnete Schnittstelle. Wenn Sie eine Erweiterung erhalten, müssen Sie bestätigen, dass der Typ der Erweiterung wie erwartet ist. Sie können Erweiterungen nur über den Prozess festlegen, der einen Binder bereitstellt.

Verwenden Sie angehängte Erweiterungen immer dann, wenn eine Erweiterung die Funktionalität eines vorhandenen HAL ändert. Wenn eine völlig neue Funktion benötigt wird, ist dieser Mechanismus nicht erforderlich und Sie können eine Erweiterungsschnittstelle direkt beim Dienstmanager registrieren. Angehängte Erweiterungsschnittstellen sind am sinnvollsten, wenn sie an Unterschnittstellen angehängt werden, da diese Hierarchien tief oder mehrfach instanziiert sein können. Wenn Sie eine globale Erweiterung verwenden, um die Binder-Schnittstellenhierarchie eines anderen Dienstes zu spiegeln, ist ein erheblicher Verwaltungsaufwand erforderlich, um die gleichen Funktionen wie bei direkt angehängten Erweiterungen zu bieten.

Verwenden Sie die folgenden APIs, um eine Erweiterung für einen Binder festzulegen:

  • NDK-Backend: AIBinder_setExtension
  • Java-Backend: android.os.Binder.setExtension
  • CPP-Backend: android::Binder::setExtension
  • Rust-Backend: binder::Binder::set_extension

Verwenden Sie die folgenden APIs, um eine Erweiterung für einen Ordner zu erhalten:

  • NDK-Backend: AIBinder_getExtension
  • Java-Backend: android.os.IBinder.getExtension
  • CPP-Backend: android::IBinder::getExtension
  • Rust-Backend: binder::Binder::get_extension

Weitere Informationen zu diesen APIs finden Sie in der Dokumentation der Funktion getExtension im entsprechenden Backend. Ein Beispiel für die Verwendung von Erweiterungen finden Sie unter hardware/interfaces/tests/extension/vibrator.

Wichtige Unterschiede zwischen AIDL und HIDL

Wenn Sie AIDL-HALs oder AIDL-HAL-Schnittstellen verwenden, sollten Sie sich der Unterschiede im Vergleich zum Schreiben von HIDL-HALs bewusst sein.

  • Die Syntax der AIDL-Sprache ähnelt eher Java. Die HIDL-Syntax ähnelt C++.
  • Alle AIDL-Schnittstellen haben integrierte Fehlerstatus. Anstatt benutzerdefinierte Statustypen zu erstellen, sollten Sie konstante Status-Ints in Schnittstellendateien erstellen und EX_SERVICE_SPECIFIC im CPP- und NDK-Backend sowie ServiceSpecificException im Java-Backend verwenden. Weitere Informationen finden Sie unter Fehlerbehandlung.
  • AIDL startet Threadpools nicht automatisch, wenn Binder-Objekte gesendet werden. Sie müssen sie manuell starten (siehe Unterhaltungsverwaltung).
  • AIDL wird bei nicht überprüften Transportfehlern nicht abgebrochen (HIDL Return wird bei nicht überprüften Fehlern abgebrochen).
  • In AIDL kann nur ein Typ pro Datei deklariert werden.
  • AIDL-Argumente können zusätzlich zum Ausgabeparameter als in, out oder inout angegeben werden (es gibt keine synchronen Callbacks).
  • In AIDL wird fd anstelle von handle als primitiver Typ verwendet.
  • HIDL verwendet Hauptversionen für inkompatible Änderungen und Nebenversionen für kompatible Änderungen. In AIDL werden abwärtskompatible Änderungen direkt vorgenommen. AIDL hat kein explizites Konzept für Hauptversionen. Stattdessen ist dies in Paketnamen enthalten. AIDL verwendet beispielsweise den Paketnamen bluetooth2.
  • AIDL erbt die Echtzeitpriorität nicht standardmäßig. Die Funktion setInheritRt muss pro Binder verwendet werden, um die Echtzeit-Prioritätsvererbung zu aktivieren.

Tests für HALs

In diesem Abschnitt werden Best Practices für das Testen von HALs beschrieben. Diese Vorgehensweisen gelten auch dann, wenn der Integrationstest für Ihr HAL nicht in VTS enthalten ist.

Android verwendet VTS, um die erwarteten HAL-Implementierungen zu überprüfen. VTS trägt dazu bei, dass Android abwärtskompatibel mit alten Anbieterimplementierungen ist. Implementierungen, die den VTS nicht bestehen, haben bekannte Kompatibilitätsprobleme, die dazu führen können, dass sie mit zukünftigen Versionen des Betriebssystems nicht funktionieren.

VTS für HALs besteht aus zwei Hauptteilen.

1. Prüfen, ob die HALs auf dem Gerät von Android erkannt und erwartet werden

Android benötigt eine statische, genaue Liste aller installierten HALs. Diese Liste wird im VINTF-Manifest angegeben. Spezielle plattformweite Tests überprüfen die Integrität der HAL-Ebenen im gesamten System. Bevor Sie HAL-spezifische Tests schreiben, sollten Sie auch diese Tests ausführen, da sie Aufschluss darüber geben können, ob eine HAL inkonsistente VINTF-Konfigurationen hat.

Diese Tests finden Sie in test/vts-testcase/hal/treble/vintf. Wenn Sie an einer Vendor-HAL-Implementierung arbeiten, verwenden Sie vts_treble_vintf_vendor_test, um sie zu überprüfen. Sie können diesen Test mit dem Befehl atest vts_treble_vintf_vendor_test ausführen.

Mit diesen Tests wird Folgendes überprüft:

  • Jede @VintfStability-Schnittstelle, die in einem VINTF-Manifest deklariert ist, wird in einer bekannten veröffentlichten Version eingefroren. So wird überprüft, ob beide Seiten der Schnittstelle mit der genauen Definition dieser Version der Schnittstelle übereinstimmen. Dies ist für den grundlegenden Betrieb erforderlich.
  • Alle HALs, die in einem VINTF-Manifest deklariert sind, sind auf diesem Gerät verfügbar. Jeder Client mit ausreichenden Berechtigungen zur Verwendung eines deklarierten HAL-Dienstes muss diese Dienste jederzeit abrufen und verwenden können.
  • Alle HALs, die in einem VINTF-Manifest deklariert sind, verwenden die Version der Schnittstelle, die sie im Manifest deklarieren.
  • Auf einem Gerät werden keine eingestellten HALs bereitgestellt. Android stellt die Unterstützung für niedrigere Versionen von HAL-Schnittstellen ein, wie im FCM-Lebenszyklus beschrieben.
  • Die erforderlichen HALs sind auf dem Gerät vorhanden. Einige HALs sind erforderlich, damit Android richtig funktioniert.

2. Erwartetes Verhalten jedes HAL prüfen

Für jede HAL-Schnittstelle gibt es eigene VTS-Tests, um das erwartete Verhalten ihrer Clients zu überprüfen. Die Testläufe werden für jede Instanz einer deklarierten HAL-Schnittstelle ausgeführt und erzwingen ein bestimmtes Verhalten basierend auf der Version der implementierten Schnittstelle.

In C++ können Sie mit der Funktion android::getAidlHalInstanceNames in libaidlvintf_gtest_helper eine Liste aller auf dem System installierten HALs abrufen. Verwenden Sie in Rust binder::get_declared_instances.

Diese Tests sollen alle Aspekte der HAL-Implementierung abdecken, auf die sich das Android-Framework stützt oder in Zukunft stützen könnte.

Dazu gehören die Überprüfung der Unterstützung von Funktionen, der Fehlerbehandlung und jedes andere Verhalten, das ein Client vom Dienst erwarten könnte.

VTS-Meilensteine für die HAL-Entwicklung

VTS-Tests (oder beliebige Tests) müssen beim Erstellen oder Ändern der HAL-Schnittstellen von Android auf dem neuesten Stand gehalten werden.

VTS-Tests müssen abgeschlossen und bereit sein, um Anbieterimplementierungen zu überprüfen, bevor sie für Android Vendor API-Releases eingefroren werden. Sie müssen bereit sein, bevor die Schnittstellen eingefroren werden, damit Entwickler ihre Implementierungen erstellen, sie überprüfen und Feedback an die Entwickler der HAL-Schnittstelle geben können.

Auf Cuttlefish testen

Wenn keine Hardware verfügbar ist, verwendet Android Cuttlefish als Entwicklungstool für HAL-Schnittstellen. Dies ermöglicht skalierbare Integrationstests von Android.

hal_implementation_test prüft, ob Cuttlefish Implementierungen der neuesten HAL-Schnittstellenversionen hat, damit Android für die neuen Schnittstellen bereit ist und die VTS-Tests die neuen Anbieterimplementierungen testen können, sobald neue Hardware und Geräte verfügbar sind.