Android O riprogetta il sistema operativo Android per definire interfacce chiare tra la piattaforma Android indipendente dal dispositivo e il codice specifico del dispositivo e del fornitore. Android definisce già molte di queste interfacce sotto forma di interfacce HAL, definite come header C in hardware/libhardware
. HIDL sostituisce queste interfacce HAL con interfacce stabili, con versione, che possono essere interfacce HIDL lato client e lato server in C++ (descritto di seguito) o Java .
Le pagine in questa sezione descrivono le implementazioni C++ delle interfacce HIDL, inclusi i dettagli sui file generati automaticamente dai file .hal .hal
dal compilatore hidl-gen
, come questi file sono impacchettati e come integrare questi file con il codice C++ che li usa.
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 metodi su di essa.
- Un server è un'implementazione di un'interfaccia HIDL che riceve chiamate dai client e restituisce risultati (se necessario).
Nella transizione da libhardware
a HAL HIDL, l'implementazione HAL diventa il server e il processo che chiama nell'HAL diventa il client. Le implementazioni predefinite possono servire sia HAL passthrough che binderizzati e possono cambiare nel tempo:
Figura 1. Progressione dello sviluppo per HAL legacy.
Creazione del client HAL
Inizia includendo le librerie HAL nel makefile:
- Crea:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
- A breve:
shared_libs: [ …, android.hardware.nfc@1.0 ]
Successivamente, includi i file di intestazione HAL:
#include <android/hardware/nfc/1.0/IFoo.h> … // in code: sp<IFoo> client = IFoo::getService(); client->doThing();
Creazione del server HAL
Per creare l'implementazione HAL, devi avere i file .hal
che rappresentano il tuo HAL e aver già generato makefile per il tuo HAL usando -Lmakefile
o -Landroidbp
su hidl-gen
( ./hardware/interfaces/update-makefiles.sh
lo fa per file HAL interni ed è un buon riferimento). Quando trasferisci su HAL da libhardware
, puoi fare molto di questo lavoro facilmente usando c2hal.
Per creare i file necessari per implementare il tuo 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é HAL funzioni in modalità passthrough, è necessario che la funzione HIDL_FETCH_IModuleName risieda 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 precedenti, 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
usa -foo
per differenziarsi.
Se un HAL è una versione minore o un'estensione di un altro HAL, l'HAL di base dovrebbe essere utilizzato per denominare questo binario. Ad esempio, le implementazioni di android.hardware.graphics.mapper@2.1
dovrebbero essere ancora in un binario chiamato android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER )
. Di solito, OPTIONAL_IDENTIFIER qui includerebbe la versione HAL effettiva. Denominando il file binario in questo modo, i client 2.0 possono recuperarlo direttamente e i client 2.1 possono eseguire l'upcast dell'implementazione.
Quindi, compila gli stub con funzionalità e imposta un demone. Esempio di codice daemon (che supporta il passthrough):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
dlopen()
la libreria -impl
fornita e la fornirà come servizio legato. Esempio di codice demone (per puro servizio binderizzato):
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 }
Questo demone di solito vive in $PACKAGE + "-service-suffix"
(ad esempio, android.hardware.nfc@1.0-service
), ma potrebbe essere ovunque. La sepolicy per una classe specifica di HAL è l'attributo hal_<module>
(ad esempio, hal_nfc)
. Questo attributo deve essere applicato al demone che esegue un particolare HAL (se lo stesso processo serve più HAL, possono essere applicati più attributi).