Dans Android 8.0, l'architecture de l'OS Android a été repensée pour définir des interfaces claires entre la plate-forme Android indépendante de l'appareil et le code spécifique à l'appareil et au fournisseur. Android a déjà défini de nombreuses interfaces de ce type sous la forme d'interfaces HAL, définies comme des en-têtes C dans hardware/libhardware
. HIDL a remplacé ces interfaces HAL par des interfaces stables et versionnées, qui peuvent être en Java (décrit ci-dessous) ou des interfaces HIDL côté client et côté serveur en C++.
Les interfaces HIDL sont destinées à être utilisées principalement à partir de code natif. Par conséquent, HIDL se concentre sur la génération automatique de code efficace en C++. Toutefois, les interfaces HIDL doivent également être disponibles pour être utilisées directement à partir de Java, car certains sous-systèmes Android (tels que Telephony) disposent d'interfaces HIDL Java.
Les pages de cette section décrivent le frontend Java pour les interfaces HIDL, expliquent comment créer, enregistrer et utiliser des services, et expliquent comment les HAL et les clients HAL écrits en Java interagissent avec le système RPC HIDL.
Exemple client
Il s'agit d'un exemple de client pour une interface IFoo
dans le package android.hardware.foo@1.0
enregistré en tant que nom de service default
et d'un service supplémentaire avec le nom de service personnalisé second_impl
.
Ajouter des bibliothèques
Vous devez ajouter des dépendances sur la bibliothèque de bouchons HIDL correspondante si vous souhaitez l'utiliser. Il s'agit généralement d'une bibliothèque statique:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Si vous savez que vous importez déjà des dépendances sur ces bibliothèques, vous pouvez également utiliser l'association partagée:
// in Android.bp libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Informations supplémentaires sur l'ajout de bibliothèques dans Android 10
Si vous disposez d'une application système ou d'un fournisseur qui cible Android 10 ou une version ultérieure, vous pouvez inclure ces bibliothèques de manière statique. Vous pouvez également utiliser (uniquement) des classes HIDL à partir de fichiers JAR personnalisés installés sur l'appareil avec des API Java stables mises à disposition à l'aide du mécanisme uses-library
existant pour les applications système. Cette dernière approche permet de gagner de l'espace sur l'appareil. Pour en savoir plus, consultez Implémenter la bibliothèque du SDK Java. Pour les anciennes applications, l'ancien comportement est conservé.
À partir d'Android 10, des versions "superficielles" de ces bibliothèques sont également disponibles. Ils incluent la classe en question, mais aucune des classes dépendantes. Par exemple, android.hardware.foo-V1.0-java-shallow
inclut des classes dans le package foo, mais n'inclut pas de classes dans android.hidl.base-V1.0-java
, qui contient la classe de base de toutes les interfaces HIDL. Si vous créez une bibliothèque qui dispose déjà des classes de base de l'interface préférée en tant que dépendance, vous pouvez utiliser ce qui suit:
// 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
Les bibliothèques de base et de gestion HIDL ne sont plus disponibles sur le chemin d'accès au chargement de l'application (auparavant, elles étaient parfois utilisées comme API masquées, en raison du chargeur de classe de premier délégué d'Android). Au lieu de cela, ils ont été déplacés vers un nouvel espace de noms avec jarjar
, et les applications qui les utilisent (applications privées nécessairement) doivent disposer de leurs propres copies distinctes. Les modules du classpath de démarrage utilisant HIDL doivent utiliser les variantes peu profondes de ces bibliothèques Java et ajouter jarjar_rules: ":framework-jarjar-rules"
à leur Android.bp
pour utiliser la version de ces bibliothèques qui existe dans le classpath de démarrage.
Modifier votre source Java
Il n'existe qu'une seule version (@1.0
) de ce service. Par conséquent, ce code ne récupère que cette version. Pour savoir comment gérer plusieurs versions différentes du service, consultez les extensions d'interface.
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(…);
Fournir un service
Le code du framework en Java peut devoir servir des interfaces pour recevoir des rappels asynchrones à partir des HAL.
Pour l'interface IFooCallback
de la version 1.0 du package android.hardware.foo
, vous pouvez implémenter votre interface en Java en procédant comme suit:
- Définissez votre interface dans HIDL.
- Ouvrez
/tmp/android/hardware/foo/IFooCallback.java
à titre de référence. - Créez un module pour votre implémentation Java.
- Examinez la classe abstraite
android.hardware.foo.V1_0.IFooCallback.Stub
, puis écrivez une classe pour l'étendre et implémenter les méthodes abstraites.
Afficher les fichiers générés automatiquement
Pour afficher les fichiers générés automatiquement, exécutez la commande suivante:
hidl-gen -o /tmp -Ljava \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0
Ces commandes génèrent le répertoire /tmp/android/hardware/foo/1.0
. Pour le fichier hardware/interfaces/foo/1.0/IFooCallback.hal
, cela génère le fichier /tmp/android/hardware/foo/1.0/IFooCallback.java
, qui encapsule l'interface Java, le code du proxy et les bouchons (le proxy et les bouchons sont conformes à l'interface).
-Lmakefile
génère les règles qui exécutent cette commande au moment de la compilation et vous permet d'inclure android.hardware.foo-V1.0-java
et d'établir des liens avec les fichiers appropriés. Vous trouverez un script qui effectue automatiquement cette opération pour un projet rempli d'interfaces sur hardware/interfaces/update-makefiles.sh
.
Les chemins d'accès de cet exemple sont relatifs. Les interfaces matérielles peuvent être un répertoire temporaire sous votre arborescence de code pour vous permettre de développer un HAL avant de le publier.
Exécuter un service
Le HAL fournit l'interface IFoo
, qui doit effectuer des rappels asynchrones vers le framework via l'interface IFooCallback
. L'interface IFooCallback
n'est pas enregistrée par nom en tant que service détectable. À la place, IFoo
doit contenir une méthode telle que setFooCallback(IFooCallback x)
.
Pour configurer IFooCallback
à partir de la version 1.0 du package android.hardware.foo
, ajoutez android.hardware.foo-V1.0-java
à Android.mk
. Le code permettant d'exécuter le service est le suivant:
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);
Extensions d'interface
En supposant qu'un service donné implémente l'interface IFoo
sur tous les appareils, il est possible que, sur un appareil particulier, le service fournisse des fonctionnalités supplémentaires implémentées dans l'extension d'interface IBetterFoo
, comme suit:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
Le code d'appel conscient de l'interface étendue peut utiliser la méthode Java castFrom()
pour caster de manière sécurisée l'interface de base en interface étendue:
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. }