Android 8 riprogetta il sistema operativo Android per definire interfacce chiare tra la piattaforma Android indipendente dal dispositivo e il codice specifico per il dispositivo e il fornitore.
Android definisce già molte di queste interfacce sotto forma di interfacce HAL,
definite come intestazioni C in hardware/libhardware
. HIDL sostituisce queste interfacce HAL con interfacce stabili e con versione, che possono essere interfacce HIDL lato client e lato server in C++ (descritte di seguito) o in Java.
Le pagine di questa sezione descrivono le implementazioni C++ delle interfacce HIDL, inclusi i dettagli sui file generati automaticamente dai file .hal
HIDL dal compilatore hidl-gen
, sulla modalità di pacchettizzamento di questi file e su come integrarli con il codice C++ che li utilizza.
Implementazioni client e server
Le interfacce HIDL hanno implementazioni client e server:
- Un client di un'interfaccia HIDL è il codice che utilizza l'interfaccia chiamando i relativi metodi.
- Un server è un'implementazione di un'interfaccia HIDL che riceve chiamate dai client e restituisce risultati (se necessario).
Durante la transizione dalle HAL libhardware
alle HAL HIDL, l'implementazione HAL diventa il server e il processo che chiama l'HAL diventa il client. Le implementazioni predefinite possono servire sia HAL passthrough che con binder e possono cambiare nel tempo:
Figura 1. Progressione dello sviluppo per gli HAL legacy.
Crea il client HAL
Inizia includendo le librerie HAL nel file makefile:
- Marca:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
- Soong:
shared_libs: [ …, android.hardware.nfc@1.0 ]
Poi, includi i file di intestazione HAL:
#include <android/hardware/nfc/1.0/IFoo.h> … // in code: sp<IFoo> client = IFoo::getService(); client->doThing();
Crea il server HAL
Per creare l'implementazione HAL, devi disporre dei file .hal
che rappresentano l'HAL e aver già generato i file make per l'HAL utilizzando
-Lmakefile
o -Landroidbp
su hidl-gen
(./hardware/interfaces/update-makefiles.sh
esegue questa operazione per i file HAL interni ed è un buon riferimento). Quando trasferisci gli HAL da
libhardware
, puoi svolgere gran parte di questo lavoro facilmente utilizzando c2hal.
Per creare i file necessari per implementare l'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
Affinché l'HAL funzioni in modalità passthrough, devi avere la funzione HIDL_FETCH_IModuleName
in /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so
, dove OPTIONAL_IDENTIFIER è una stringa che identifica l'implementazione passthrough. I requisiti della modalità passthrough vengono soddisfatti automaticamente dai comandi riportati sopra, che creano anche la destinazione android.hardware.nfc@1.0-impl
, ma è possibile utilizzare qualsiasi estensione. Ad esempio, android.hardware.nfc@1.0-impl-foo
utilizza -foo
per distinguersi.
Se un HAL è una versione minore o un'estensione di un altro HAL, deve essere utilizzato l'HAL di base per assegnare un nome a questo file binario. Ad esempio,
le implementazioni di android.hardware.graphics.mapper@2.1
dovrebbero
essere ancora in un file binario chiamato
android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER)
.
Di solito, OPTIONAL_IDENTIFIER qui include la versione HAL effettiva. Se il file binario viene denominato in questo modo, i client 2.0 possono recuperarlo direttamente e i client 2.1 possono eseguire l'upcast dell'implementazione.
Successivamente, compila gli stub con la funzionalità e configura un demone. Codice del daemon di esempio (supporta il passthrough):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
chiama
dlopen()
per la libreria -impl
fornita e la fornisce come
un servizio incapsulato. Codice di esempio del demone (per un servizio completamente incapsulato):
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 }
Questo demone di solito si trova in $PACKAGE + "-service-suffix"
(ad es. android.hardware.nfc@1.0-service
), ma potrebbe trovarsi ovunque.
sepolicy per una specifica
classe di HAL è l'attributo hal_<module>
(ad esempio,
hal_nfc)
. Questo attributo deve essere applicato al daemon che esegue un determinato HAL (se lo stesso processo serve più HAL, è possibile applicare più attributi).