In Android 8.0, il sistema operativo Android è stato riprogettato per definire interfacce chiare tra la piattaforma Android indipendente dal dispositivo e il codice specifico per il dispositivo e il fornitore. Android ha già definito molte di queste interfacce sotto forma di interfacce HAL, definite come intestazioni C in hardware/libhardware
. HIDL
ha sostituito queste interfacce HAL con interfacce stabili e con versione, che possono essere in Java (descritto di seguito) o interfacce HIDL lato client e lato server in C++.
Le interfacce HIDL sono progettate per essere utilizzate principalmente dal codice nativo e, di conseguenza, HIDL si concentra sulla generazione automatica di codice efficiente in C++. Tuttavia, le interfacce HIDL devono essere disponibili anche per l'utilizzo direttamente da Java, poiché alcuni sottosistemi Android (come Telephony) hanno interfacce HIDL Java.
Le pagine di questa sezione descrivono il frontend Java per le interfacce HIDL, illustrano come creare, registrare e utilizzare i servizi e spiegano come gli HAL e i client HAL scritti in Java interagiscono con il sistema RPC HIDL.
Esempio di client
Questo è un esempio di client per un'interfaccia IFoo
nel pacchetto
android.hardware.foo@1.0
registrato come nome servizio
default
e un servizio aggiuntivo con il nome servizio personalizzato
second_impl
.
Aggiungere librerie
Se vuoi utilizzarla, devi aggiungere le dipendenze alla libreria stub HIDL corrispondente. Di solito si tratta di una libreria statica:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Se sai che stai già importando dipendenze da queste librerie, puoi anche utilizzare il collegamento condiviso:
// in Android.bp libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Considerazioni aggiuntive per l'aggiunta di librerie in Android 10
Se hai un'app di sistema o del fornitore che ha come target Android 10 o versioni successive, puoi includere queste librerie in modo statico. Puoi anche utilizzare (solo) le classi HIDL
da JAR personalizzati installati sul dispositivo con API Java stabili messe a disposizione
utilizzando il meccanismo uses-library
esistente per le app di sistema. L'approccio
secondo consente di risparmiare spazio sul dispositivo. Per maggiori dettagli, consulta Implementazione della libreria SDK Java. Per le app meno recenti, viene mantenuto il vecchio comportamento.
A partire da Android 10, sono disponibili anche versioni "superficiali" di queste librerie. Sono incluse la classe in questione, ma non le classi dipendenti. Ad esempio,
android.hardware.foo-V1.0-java-shallow
include le classi nel pacchetto foo, ma non include le classi in
android.hidl.base-V1.0-java
, che contiene la classe di base di tutte le
interfacce HIDL. Se stai creando una libreria che ha già le classi di base dell'interfaccia preferita disponibili come dipendenza, puoi utilizzare quanto segue:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java-shallow", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow
Inoltre, le librerie di base e di gestione HIDL non sono più disponibili nel percorso di classe di avvio per le app (in precedenza, a volte venivano utilizzate come API nascoste, a causa del caricatore delle classi di Android in primo piano). Sono stati invece spostati in un nuovo spazio dei nomi con jarjar
e le app che li utilizzano (necessariamente private) devono avere copie separate. I moduli nel percorso di classe di avvio che utilizzano HIDL devono utilizzare le varianti superficiali di queste librerie Java e aggiungere jarjar_rules: ":framework-jarjar-rules"
al loro Android.bp
per utilizzare la versione di queste librerie esistente nel percorso di classe di avvio.
Modificare il codice sorgente Java
Esiste una sola versione (@1.0
) di questo servizio, pertanto questo codice recupera solo quella versione. Consulta le estensioni dell'interfaccia per scoprire come gestire più versioni diverse del servizio.
import android.hardware.foo.V1_0.IFoo; ... // retry to wait until the service starts up if it is in the manifest IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available IFoo anotherServer = IFoo.getService("second_impl", true /* retry */); server.doSomething(…);
Fornire un servizio
Il codice del framework in Java potrebbe dover fornire interfacce per ricevere callback asincroni dalle HAL.
Per l'interfaccia IFooCallback
nella versione 1.0 del
pacchetto android.hardware.foo
, puoi implementare l'interfaccia in Java seguendo questi passaggi:
- Definisci l'interfaccia in HIDL.
- Apri
/tmp/android/hardware/foo/IFooCallback.java
come riferimento. - Crea un nuovo modulo per l'implementazione Java.
- Esamina la classe astratta
android.hardware.foo.V1_0.IFooCallback.Stub
, poi scrivi una nuova classe per estenderla e implementare i metodi astratti.
Visualizzare i file generati automaticamente
Per visualizzare i file generati automaticamente, esegui:
hidl-gen -o /tmp -Ljava \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0
Questi comandi generano la directory/tmp/android/hardware/foo/1.0
. Per il file
hardware/interfaces/foo/1.0/IFooCallback.hal
, viene generato il
file /tmp/android/hardware/foo/1.0/IFooCallback.java
, che
incapsula l'interfaccia Java, il codice proxy e gli stub (sia il proxy che
gli stub sono conformi all'interfaccia).
-Lmakefile
genera le regole che eseguono questo comando al momento della compilazione e ti consentono di includereandroid.hardware.foo-V1.0-java
e creare link ai file appropriati. Uno script che esegue automaticamente questa operazione per un progetto pieno di interfacce è disponibile all'indirizzo hardware/interfaces/update-makefiles.sh
.
I percorsi in questo esempio sono relativi; hardware/interfaces può essere una directory temporanea nella struttura ad albero del codice per consentirti di sviluppare un HAL prima di pubblicarlo.
Eseguire un servizio
L'HAL fornisce l'interfaccia IFoo
, che deve eseguire chiamate di callback asincrone al framework tramite l'interfaccia IFooCallback
. L'interfaccia IFooCallback
non è registrata per nome come servizio rilevabile; IFoo
deve invece contenere un metodo come setFooCallback(IFooCallback x)
.
Per configurare IFooCallback
dalla versione 1.0 del pacchettoandroid.hardware.foo
, aggiungiandroid.hardware.foo-V1.0-java
a Android.mk
. Il codice per eseguire il servizio è:
import android.hardware.foo.V1_0.IFoo; import android.hardware.foo.V1_0.IFooCallback.Stub; .... class FooCallback extends IFooCallback.Stub { // implement methods } .... // Get the service from which you will be receiving callbacks. // This also starts the threadpool for your callback service. IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available .... // This must be a persistent instance variable, not local, // to avoid premature garbage collection. FooCallback mFooCallback = new FooCallback(); .... // Do this once to create the callback service and tell the "foo-bar" service server.setFooCallback(mFooCallback);
Estensioni dell'interfaccia
Supponendo che un determinato servizio implementi l'interfaccia IFoo
su tutti i dispositivi, è possibile che su un determinato dispositivo il servizio fornisca funzionalità aggiuntive implementate nell'estensione dell'interfaccia IBetterFoo
, come segue:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
Il codice di chiamata consapevole dell'interfaccia estesa può utilizzare il metodo Java castFrom()
per eseguire il casting sicuro dell'interfaccia di base all'interfaccia estesa:
IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available IBetterFoo extendedService = IBetterFoo.castFrom(baseService); if (extendedService != null) { // The service implements the extended interface. } else { // The service implements only the base interface. }