HIDL Java

Dans Android 8.0, le système d'exploitation Android a été repensé 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 déjà défini plusieurs de ces interfaces sous la forme d'interfaces HAL, définies comme les en- têtes C dans le hardware/libhardware . HIDL remplacé ces interfaces HAL avec des interfaces stables, version, qui peut être soit en Java (décrit ci - dessous) ou être des interfaces de HIDL côté client et côté serveur en C ++ .

Les interfaces HIDL sont destinées à être utilisées principalement à partir de code natif et, par conséquent, HIDL se concentre sur la génération automatique de code efficace en C++. Cependant, les interfaces HIDL doivent également être disponibles pour une utilisation directement à partir de Java, car certains sous-systèmes Android (tels que la téléphonie) ont des interfaces Java HIDL.

Les pages de cette section décrivent l'interface Java pour les interfaces HIDL, détaillent 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 HIDL RPC.

Être client

Ceci est un exemple d'un client pour une interface IFoo dans le paquet android.hardware.foo@1.0 qui est enregistré comme nom de service par default et un service supplémentaire avec le nom du service personnalisé second_impl .

Ajout de bibliothèques

Vous devez ajouter des dépendances sur la bibliothèque de stub HIDL correspondante si vous souhaitez l'utiliser. Habituellement, il s'agit 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 extrayez déjà des dépendances sur ces bibliothèques, vous pouvez également utiliser une liaison partagée :

// in Android.bp
libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Considérations supplémentaires pour 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 (seulement) des classes de HIDL de JARs personnalisés installés sur l'appareil avec stables API Java mis à disposition en utilisant les existants uses-library mécanisme pour les applications du système. Cette dernière approche permet d'économiser de l'espace sur l'appareil. Pour plus de détails, consultez la section Implémentation Java SDK Library . Pour les anciennes applications, l'ancien comportement est conservé.

À partir d'Android 10, des versions « superficielles » de ces bibliothèques sont également disponibles. Celles-ci incluent la classe en question mais n'incluent aucune des classes dépendantes. Par exemple, android.hardware.foo-V1.0-java-shallow comprend des classes dans le paquet foo, mais ne comprend pas les classes dans android.hidl.base-V1.0-java , qui contient la classe de base de tous HIDL interfaces. Si vous créez une bibliothèque qui a déjà les classes de base de l'interface préférée disponibles en tant que dépendance, vous pouvez utiliser les éléments suivants :

// 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 également plus disponibles sur le chemin de classe de démarrage pour les applications (auparavant, elles étaient parfois utilisées comme API cachée, en raison du chargeur de classe délégué en premier d'Android). Au lieu de cela, ils ont été déplacés dans un nouvel espace de noms avec jarjar , et les applications qui utilisent ces applications (nécessairement nichées) doivent avoir leurs propres copies séparées. Modules sur le chemin de classe de démarrage à l' aide HIDL doit utiliser les eaux peu profondes variantes de ces bibliothèques Java et d'ajouter jarjar_rules: ":framework-jarjar-rules" à leur Android.bp d'utiliser la version de ces bibliothèques qui existent dans le classpath de démarrage.

Modifier votre source Java

Il n'y a qu'une seule version ( @1.0 ) de ce service, de sorte que ce code récupère uniquement cette version. Voir les extensions d' interface pour la façon de gérer plusieurs versions différentes du service.

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 avoir besoin de servir des interfaces pour recevoir des rappels asynchrones des HAL.

Pour la IFooCallback interface dans la version 1.0 du android.hardware.foo package, vous pouvez implémenter votre interface en Java en utilisant les étapes suivantes:

  1. Définissez votre interface en HIDL.
  2. Ouvrez /tmp/android/hardware/foo/IFooCallback.java comme référence.
  3. Créez un nouveau module pour votre implémentation Java.
  4. Examinez la classe abstraite android.hardware.foo.V1_0.IFooCallback.Stub , puis d' écrire une nouvelle classe pour étendre et mettre en œuvre les méthodes abstraites.

Affichage des fichiers générés automatiquement

Pour afficher les fichiers générés automatiquement, exécutez :

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 proxy, et les talons ( les deux proxy et les talons sont conformes à l'interface).

-Lmakefile génère les règles qui régissent cette commande au moment de la construction et vous permettent d'inclure android.hardware.foo-V1.0-java et un lien avec les fichiers appropriés. Un script qui fait automatiquement pour un projet complet d'interfaces sont disponibles sur le hardware/interfaces/update-makefiles.sh . Les chemins de cet exemple sont relatifs ; hardware/interfaces peut ê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

HAL offre la IFoo interface, qui doit faire callbacks asynchrones au cadre sur la IFooCallback interface. La IFooCallback interface est pas enregistrée par son nom en tant que service découvrable; à la place, IFoo doit contenir une méthode telle que setFooCallback(IFooCallback x) .

Pour configurer IFooCallback de la version 1.0 du android.hardware.foo package, ajouter android.hardware.foo-V1.0-java à Android.mk . Le code pour exécuter le service est :

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'interfaces

En supposant un outils de service étant donné la IFoo l' interface sur tous les appareils, il est possible que sur un dispositif particulier , le service pourrait fournir des capacités supplémentaires mises en œuvre dans l'extension de l' interface IBetterFoo , comme suit:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Indicatif téléphonique au courant de l'interface prolongée peut utiliser le castFrom() méthode Java en toute sécurité jeté l'interface de base à l'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.
}