HIDL C++

Mit Android 8 wird das Android-Betriebssystem neu gestaltet, um klare Schnittstellen zwischen den geräteunabhängige Android-Plattform und geräte- und anbieterspezifischer Code Android definiert bereits viele solcher Schnittstellen in Form von HAL-Schnittstellen. als C-Header in hardware/libhardware definiert. HIDL ersetzt diese HAL-Schnittstellen mit stabilen, versionierten Schnittstellen, die client- und serverseitige HIDL-Schnittstellen in C++ (siehe unten) oder Java

Die Seiten in diesem Abschnitt beschreiben die C++-Implementierungen von HIDL-Schnittstellen, einschließlich Details zu den Dateien, die automatisch aus dem HIDL .hal generiert wurden. Dateien durch den hidl-gen-Compiler, wie diese Dateien gepackt sind und wie diese Dateien in den C++-Code integriert werden, der sie verwendet.

Client- und Serverimplementierungen

HIDL-Schnittstellen haben Client- und Serverimplementierungen:

  • Ein Client einer HIDL-Schnittstelle ist der Code, der die Methode durch Aufrufen von Methoden.
  • Ein Server ist eine Implementierung einer HIDL-Schnittstelle, empfängt Aufrufe von Clients und gibt Ergebnisse zurück (falls erforderlich).

Beim Wechsel von libhardware HALs zu HIDL HALs Implementierung wird zum Server und der Aufruf in den HAL wird zu Kundschaft. Standardimplementierungen können sowohl Passthrough als auch binderisierte HALs und können sich im Laufe der Zeit ändern:

Abbildung 1: Entwicklungsfortschritt für Legacy-HALs.

HAL-Client erstellen

Beginnen Sie mit dem Einfügen der HAL-Bibliotheken in das Makefile:

  • Marke: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Titel: shared_libs: [ …, android.hardware.nfc@1.0 ]

Fügen Sie als Nächstes die HAL-Headerdateien ein:

#include <android/hardware/nfc/1.0/IFoo.h>
…
// in code:
sp<IFoo> client = IFoo::getService();
client->doThing();

HAL-Server erstellen

Zum Erstellen der HAL-Implementierung benötigen Sie die .hal-Dateien die Ihren HAL repräsentieren und bereits Makefiles für Ihren HAL mithilfe von -Lmakefile oder -Landroidbp bei hidl-gen (./hardware/interfaces/update-makefiles.sh führt dies für interne HAL-Dateien und dient als Referenz). Beim Übertragen von HALs von libhardware, kannst du viele dieser Aufgaben ganz einfach mit c2hal erledigen.

So erstellen Sie die erforderlichen Dateien zum Implementieren des 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 der HAL im Passthrough-Modus funktioniert, müssen Sie die Funktion HIDL_FETCH_IModuleName in /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so Dabei ist OPTIONAL_IDENTIFIER ein String, der das Passthrough identifiziert. Implementierung. Die Anforderungen an den Passthrough-Modus werden automatisch vom der obigen Befehle, durch die auch das android.hardware.nfc@1.0-impl-Element erstellt wird. Es kann jedoch jede Erweiterung verwendet werden. Zum Beispiel android.hardware.nfc@1.0-impl-foo verwendet -foo, um sich von anderen abheben.

Wenn ein HAL eine Nebenversion oder die Erweiterung einer anderen HAL verwenden, sollte die Basis-HAL verwendet werden, um diese Binärdatei zu benennen. Beispiel: android.hardware.graphics.mapper@2.1-Implementierungen sollten immer noch in einer Binärdatei namens android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER). Normalerweise enthält die OPTIONAL_IDENTIFIER hier den tatsächlichen HAL Version. Wenn Sie die Binärdatei so benennen, können 2.0-Clients sie direkt abrufen, und 2.1-Kunden können die Implementierung aktualisieren.

Als Nächstes füllen Sie die Stubs mit den entsprechenden Funktionen aus und richten einen Daemon ein. Beispiel Daemon-Code (mit Unterstützung für Passthrough):

#include <hidl/LegacySupport.h>

int main(int /* argc */, char* /* argv */ []) {
    return defaultPassthroughServiceImplementation<INfc>("nfc");
}

defaultPassthroughServiceImplementation Anruf dlopen() für die bereitgestellte -impl-Bibliothek und stellt sie als ein gebundener Dienst. Daemon-Beispielcode (für einen reinen binderisierten Dienst):

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 never exceeds
    // 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 in $PACKAGE + "-service-suffix" (für Beispiel: android.hardware.nfc@1.0-service), kann aber an einem beliebigen Ort sein. Die sepolicy für eine bestimmte Klasse von HALs ist das Attribut hal_<module> (z. B. hal_nfc). Dieses Attribut muss auf den Daemon angewendet werden, der einen bestimmte HAL (wenn derselbe Prozess mehrere HALs, mehrere Attribute angewendet werden kann).