Android O entwickelt das Android-Betriebssystem neu, um klare Schnittstellen zwischen der geräteunabhängigen Android-Plattform und geräte- und herstellerspezifischem Code zu definieren. Android definiert bereits viele solcher Schnittstellen in Form von HAL-Schnittstellen, die in hardware/libhardware
als C-Header hardware/libhardware
. HIDL ersetzt diese HAL-Schnittstellen durch stabile, versionierte Schnittstellen, bei denen es sich um clientseitige und serverseitige HIDL-Schnittstellen in C ++ (siehe unten) oder Java handeln kann .
Die Seiten in diesem Abschnitt beschreiben C ++ - Implementierungen von HIDL-Schnittstellen, einschließlich Details zu den Dateien, die vom hidl-gen
Compiler automatisch aus den HIDL .hal
Dateien hidl-gen
, wie diese Dateien hidl-gen
werden und wie diese Dateien in den C ++ - Code integriert werden benutzt sie.
Client & Server-Implementierungen
HIDL-Schnittstellen haben Client- und Server-Implementierungen:
- Ein Client einer HIDL-Schnittstelle ist der Code, der die Schnittstelle durch Aufrufen von Methoden verwendet.
- Ein Server ist eine Implementierung einer HIDL-Schnittstelle, die Anrufe von Clients empfängt und Ergebnisse zurückgibt (falls erforderlich).
Beim Übergang von libhardware
HALs zu HIDL-HALs wird die HAL-Implementierung zum Server und der in die HAL aufrufende Prozess zum Client. Standardimplementierungen können sowohl Passthrough- als auch Binder-HALs bedienen und sich im Laufe der Zeit ändern:
Abbildung 1. Entwicklungsfortschritt für ältere HALs.
Erstellen des HAL-Clients
Beginnen Sie, indem Sie die HAL-Bibliotheken in das Makefile aufnehmen:
- Machen Sie:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
- Soong:
shared_libs: [ …, android.hardware.nfc@1.0 ]
Fügen Sie als Nächstes die HAL-Header-Dateien hinzu:
#include <android/hardware/nfc/1.0/IFoo.h> … // in code: sp<IFoo> client = IFoo::getService(); client->doThing();
Erstellen des HAL-Servers
Um die HAL-Implementierung zu erstellen, müssen Sie über die .hal
Dateien verfügen, die Ihre HAL darstellen und bereits Makefiles für Ihre HAL mit -Lmakefile
oder -Landroidbp
auf hidl-gen
./hardware/interfaces/update-makefiles.sh
( ./hardware/interfaces/update-makefiles.sh
erledigt dies für interne HAL-Dateien und ist eine gute Referenz). Wenn Sie HALs von libhardware
, können Sie einen Großteil dieser Arbeit problemlos mit c2hal erledigen.
So erstellen Sie die erforderlichen Dateien zur Implementierung Ihrer HAL:
PACKAGE=android.hardware.nfc@1.0 LOC=hardware/interfaces/nfc/1.0/default/ m -j hidl-gen hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE
Damit die HAL im Passthrough-Modus funktioniert, muss sich die Funktion HIDL_FETCH_IModuleName in /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so
Dabei ist OPTIONAL_IDENTIFIER eine Zeichenfolge, die die Passthrough-Implementierung identifiziert. Die Anforderungen für den Passthrough-Modus werden automatisch von den obigen Befehlen erfüllt, die auch das Ziel android.hardware.nfc@1.0-impl
erstellen. android.hardware.nfc@1.0-impl
kann jedoch jede Erweiterung verwendet werden. Zum Beispiel android.hardware.nfc@1.0-impl-foo
Anwendungen -foo
selbst zu unterscheiden.
Wenn eine HAL eine Nebenversion oder eine Erweiterung einer anderen HAL ist, sollte die Basis-HAL verwendet werden, um diese Binärdatei zu benennen. Beispielsweise android.hardware.graphics.mapper@2.1
Implementierungen von android.hardware.graphics.mapper@2.1
weiterhin in einer Binärdatei mit dem Namen android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER )
. Normalerweise enthält der OPTIONAL_IDENTIFIER hier die aktuelle HAL-Version. Wenn Sie die Binärdatei so benennen, können 2.0-Clients sie direkt abrufen und 2.1-Clients können die Implementierung aktualisieren.
Füllen Sie als Nächstes die Stubs mit Funktionen aus und richten Sie einen Daemon ein. Beispiel-Daemon-Code (unterstützt Passthrough):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
dlopen()
die bereitgestellte -impl
Bibliothek und stellt sie als binderisierten Dienst bereit. Beispiel-Daemon-Code (für reinen Binder-Service):
int main(int /* argc */, char* /* argv */ []) { // This function must be called before you join to ensure the proper // number of threads are created. The threadpool will never exceed // size one because of this call. ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); sp<INfc> nfc = new Nfc(); const status_t status = nfc->registerAsService(); if (status != ::android::OK) { return 1; // or handle error } // Adds this thread to the threadpool, resulting in one total // thread in the threadpool. We could also do other things, but // would have to specify 'false' to willJoin in configureRpcThreadpool. ::android::hardware::joinRpcThreadpool(); return 1; // joinRpcThreadpool should never return }
Dieser Daemon befindet sich normalerweise im $PACKAGE + "-service-suffix"
(z. B. android.hardware.nfc@1.0-service
), kann aber überall sein. Die Sepolitik für eine bestimmte Klasse von HALs ist das Attribut hal_<module>
(zum Beispiel hal_nfc)
. Dieses Attribut muss auf den Dämon angewendet werden, auf dem eine bestimmte HAL ausgeführt wird (wenn derselbe Prozess mehrere HALs bedient, können mehrere Attribute darauf angewendet werden).