HIDL-C++

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Android O gestaltet das Android-Betriebssystem neu, um klare Schnittstellen zwischen der geräteunabhängigen Android-Plattform und geräte- und anbieterspezifischem Code zu definieren. Android definiert bereits viele solcher Schnittstellen in Form von HAL-Schnittstellen, die als C-Header in hardware/libhardware definiert sind. HIDL ersetzt diese HAL-Schnittstellen durch stabile, versionierte Schnittstellen, die client- und serverseitige HIDL-Schnittstellen in C++ (unten beschrieben) oder Java sein können.

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 generiert werden, wie diese Dateien verpackt werden und wie diese Dateien in den C++-Code integriert werden verwendet sie.

Client- und Serverimplementierungen

HIDL-Schnittstellen haben Client- und Serverimplementierungen:

  • Ein Client einer HIDL-Schnittstelle ist der Code, der die Schnittstelle verwendet, indem er Methoden darauf aufruft.
  • Ein Server ist eine Implementierung einer HIDL-Schnittstelle, die Aufrufe von Clients empfängt und (falls erforderlich) Ergebnisse zurückgibt.

Beim Übergang von libhardware -HALs zu HIDL-HALs wird die HAL-Implementierung zum Server und der Prozess, der die HAL aufruft, zum Client. Standardimplementierungen können sowohl Passthrough- als auch binderisierte HALs bedienen und können sich im Laufe der Zeit ändern:

Abbildung 1. Entwicklungsfortschritt für Legacy-HALs.

Erstellen des HAL-Clients

Beginnen Sie damit, die HAL-Bibliotheken in das Makefile aufzunehmen:

  • 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 Sie müssen bereits Makefiles für Ihre HAL mit -Lmakefile oder -Landroidbp auf hidl-gen generiert haben ( ./hardware/interfaces/update-makefiles.sh tut dies für internen HAL-Dateien und ist eine gute Referenz). Beim Übertragen von HALs von libhardware können Sie einen Großteil dieser Arbeit einfach mit c2hal erledigen.

So erstellen Sie die erforderlichen Dateien zum Implementieren 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, müssen Sie die Funktion HIDL_FETCH_IModuleName in /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so wobei OPTIONAL_IDENTIFIER eine Zeichenfolge ist, 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, aber es kann jede beliebige Erweiterung verwendet werden. Zum Beispiel verwendet android.hardware.nfc@1.0-impl-foo -foo , um sich 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. Zum Beispiel sollten sich android.hardware.graphics.mapper@2.1 immer noch in einer Binärdatei namens android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Normalerweise würde der OPTIONAL_IDENTIFIER hier die tatsächliche HAL-Version enthalten. Indem Sie die Binärdatei so benennen, können 2.0-Clients sie direkt abrufen, und 2.1-Clients können die Implementierung upcasten.

Als nächstes füllen Sie die Stubs mit Funktionalität aus und richten 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 gebundenen Dienst bereit. Beispiel-Daemon-Code (für reinen gebundenen 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 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 in $PACKAGE + "-service-suffix" (z. B. android.hardware.nfc@1.0-service ), aber er könnte überall sein. Die Trennungsrichtlinie 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 eine bestimmte HAL ausführt (wenn derselbe Prozess mehrere HALs bedient, können ihm mehrere Attribute zugewiesen werden).