Android 8 riprogetta il sistema operativo Android per definire interfacce chiare tra
piattaforma Android indipendente dal dispositivo e codice specifico del dispositivo e del fornitore.
Android ha già definito molte interfacce di questo tipo sotto forma di interfacce HAL,
definita come intestazioni C in hardware/libhardware
. HIDL le sostituisce
Interfacce HAL con interfacce stabili con controllo delle versioni, che possono essere
interfacce HIDL lato server in C++ (descritte di seguito) o
Java.
Le pagine di questa sezione descrivono le implementazioni C++ delle interfacce HIDL,
inclusi i dettagli sui file generati automaticamente dal programma HIDL .hal
file dal compilatore hidl-gen
, come vengono pacchettizzati questi file e
come integrare questi file con il codice C++ che li utilizza.
Implementazioni di client e server
Le interfacce HIDL hanno implementazioni client e server:
- Un client di un'interfaccia HIDL è il codice che utilizza la proprietà richiamando metodi su quest'ultima.
- Un server è un'implementazione di un'interfaccia HIDL che riceve chiamate dai clienti e restituisce i risultati (se necessario).
Durante la transizione dagli HAL libhardware
agli HAL HIDL, l'HAL
diventa il server e il processo che chiama all'HAL diventa
il cliente. Le implementazioni predefinite possono gestire sia passthrough che binderizzate
HAL e possono cambiare nel tempo:
Figura 1. Avanzamento dello sviluppo per gli HAL precedenti.
Crea il client HAL
Inizia includendo le librerie HAL nel makefile:
- Marca:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
- Presto:
shared_libs: [ …, android.hardware.nfc@1.0 ]
Quindi, 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 il tuo HAL e che hanno già generato makefile per l'HAL utilizzando
-Lmakefile
o -Landroidbp
su hidl-gen
(./hardware/interfaces/update-makefiles.sh
lo fa per uso interno
HAL ed è un buon riferimento). Durante il trasferimento su HAL da
libhardware
, puoi svolgere facilmente molte di queste attività usando 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
all'interno
/(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so
dove OPTIONAL_IDENTIFIER è una stringa che identifica il passthrough
implementazione. I requisiti della modalità passthrough vengono soddisfatti automaticamente
precedenti, che creano anche android.hardware.nfc@1.0-impl
ma è possibile utilizzare qualsiasi estensione. Ad esempio
android.hardware.nfc@1.0-impl-foo
utilizza -foo
per
differenziarsi.
Se un HAL è una versione secondaria o un'estensione di un'altra
HAL, per assegnare un nome a questo programma binario deve essere utilizzato l'HAL di base. Ad esempio,
android.hardware.graphics.mapper@2.1
implementazioni devono
comunque essere in un file binario chiamato
android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER)
.
Solitamente, il valore OPTIONAL_IDENTIFIER qui include l'HAL effettivo
completamente gestita. Assegnando al programma binario il nome seguente, i client 2.0 possono recuperarlo direttamente,
e 2.1 possono aggiornare l'implementazione.
Quindi, compila gli stub con le funzionalità e configura un daemon. Esempio codice daemon (che supporta il passthrough):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
chiamate
dlopen()
per la libreria -impl
fornita e lo fornisce come
un servizio binderizzato. Esempio di codice daemon (per servizio binderized puro):
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 daemon solitamente risiede in $PACKAGE + "-service-suffix"
(per
esempio, android.hardware.nfc@1.0-service
), ma potrebbe essere ovunque.
Il sepolicy per uno specifico
HAL è l'attributo hal_<module>
(ad esempio,
hal_nfc)
. Questo attributo deve essere applicato al daemon che esegue un
un determinato HAL (se la stessa procedura pubblica più HAL, più attributi
possono essere applicate a quest'ultima).