In Android 8.0 wurde das Android-Betriebssystem neu gestaltet, um klare Schnittstellen zwischen der geräteunabhängigen Android-Plattform und geräte- und herstellerspezifischem Code zu definieren. Android hat bereits viele solcher Schnittstellen in Form von HAL-Schnittstellen definiert, die als C-Header in hardware/libhardware
definiert sind. HIDL hat diese HAL-Schnittstellen durch stabile, versionierte Schnittstellen ersetzt, die entweder in Java sein können (unten beschrieben) oder client- und serverseitige HIDL-Schnittstellen in C++ sein können.
HIDL-Schnittstellen sollen hauptsächlich von nativem Code verwendet werden, und daher konzentriert sich HIDL auf die automatische Generierung von effizientem Code in C++. Allerdings müssen auch HIDL-Schnittstellen für die Verwendung direkt aus Java verfügbar sein, da einige Android-Subsysteme (z. B. Telefonie) über Java-HIDL-Schnittstellen verfügen.
Die Seiten in diesem Abschnitt beschreiben das Java-Frontend für HIDL-Schnittstellen, beschreiben ausführlich, wie Dienste erstellt, registriert und verwendet werden, und erläutern, wie in Java geschriebene HALs und HAL-Clients mit dem HIDL-RPC-System interagieren.
Kunde sein
Dies ist ein Beispiel für einen Client für eine Schnittstelle IFoo
im Paket android.hardware.foo@1.0
, die als Dienstname default
registriert ist, und einen zusätzlichen Dienst mit dem benutzerdefinierten second_impl
.
Bibliotheken hinzufügen
Sie müssen Abhängigkeiten von der entsprechenden HIDL-Stub-Bibliothek hinzufügen, wenn Sie sie verwenden möchten. Normalerweise ist dies eine statische Bibliothek:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Wenn Sie wissen, dass Sie bereits Abhängigkeiten von diesen Bibliotheken ziehen, können Sie auch Shared Linkage verwenden:
// in Android.bp libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
Zusätzliche Überlegungen zum Hinzufügen von Bibliotheken in Android 10
Wenn Sie eine System- oder Anbieter-App haben, die auf Android 10 oder höher ausgerichtet ist, können Sie diese Bibliotheken statisch einschließen. Sie können auch (nur) HIDL-Klassen aus benutzerdefinierten JARs verwenden, die auf dem Gerät mit stabilen Java-APIs installiert sind, die mithilfe des vorhandenen uses-library
Mechanismus für System-Apps verfügbar gemacht werden. Der letztere Ansatz spart Platz auf dem Gerät. Weitere Einzelheiten finden Sie unter Implementieren der Java SDK-Bibliothek . Bei älteren Apps bleibt das alte Verhalten erhalten.
Ab Android 10 sind auch "flache" Versionen dieser Bibliotheken verfügbar. Dazu gehört die betreffende Klasse, aber keine der abhängigen Klassen. Beispielsweise android.hardware.foo-V1.0-java-shallow
Klassen im foo -Paket, aber keine Klassen in android.hidl.base-V1.0-java
, das die Basisklasse aller HIDL enthält Schnittstellen. Wenn Sie eine Bibliothek erstellen, die bereits die Basisklassen der bevorzugten Schnittstelle als Abhängigkeit verfügbar hat, können Sie Folgendes verwenden:
// 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
HIDL-Basis- und -Manager-Bibliotheken sind auch nicht mehr im Boot-Klassenpfad für Apps verfügbar (früher wurden sie aufgrund des Delegate-First-Klassenladers von Android manchmal als versteckte API verwendet). Stattdessen wurden sie mit jarjar
in einen neuen Namespace verschoben, und Apps, die diese verwenden (notwendigerweise private Apps), müssen ihre eigenen separaten Kopien haben. Module im Boot-Klassenpfad, die HIDL verwenden, müssen die flachen Varianten dieser Java-Bibliotheken verwenden und jarjar_rules: ":framework-jarjar-rules"
zu ihrer Android.bp
, um die Version dieser Bibliotheken zu verwenden, die im Boot-Klassenpfad vorhanden ist.
Ändern Ihrer Java-Quelle
Es gibt nur eine Version ( @1.0
) dieses Dienstes, daher ruft dieser Code nur diese Version ab. Informationen zum Umgang mit mehreren verschiedenen Versionen des Dienstes finden Sie unter Schnittstellenerweiterungen .
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(…);
Bereitstellung einer Dienstleistung
Framework-Code in Java muss möglicherweise Schnittstellen bereitstellen, um asynchrone Rückrufe von HALs zu empfangen.
Für die IFooCallback
Schnittstelle in Version 1.0 des android.hardware.foo
-Pakets können Sie Ihre Schnittstelle in Java mit den folgenden Schritten implementieren:
- Definieren Sie Ihre Schnittstelle in HIDL.
- Öffnen
/tmp/android/hardware/foo/IFooCallback.java
als Referenz. - Erstellen Sie ein neues Modul für Ihre Java-Implementierung.
- Untersuchen Sie die abstrakte Klasse
android.hardware.foo.V1_0.IFooCallback.Stub
, schreiben Sie dann eine neue Klasse, um sie zu erweitern, und implementieren Sie die abstrakten Methoden.
Anzeigen von automatisch generierten Dateien
Um die automatisch generierten Dateien anzuzeigen, führen Sie Folgendes aus:
hidl-gen -o /tmp -Ljava \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0
Diese Befehle erzeugen das Verzeichnis /tmp/android/hardware/foo/1.0
. Für die Datei hardware/interfaces/foo/1.0/IFooCallback.hal
erzeugt dies die Datei /tmp/android/hardware/foo/1.0/IFooCallback.java
, die die Java-Schnittstelle, den Proxy-Code und die Stubs (beide Proxy und Stubs entsprechen der Schnittstelle).
-Lmakefile
generiert die Regeln, die diesen Befehl zur Build-Zeit ausführen und es Ihnen ermöglichen, android.hardware.foo-V1.0-java
und mit den entsprechenden Dateien zu verknüpfen. Ein Skript, das dies für ein Projekt voller Schnittstellen automatisch erledigt, finden Sie unter hardware/interfaces/update-makefiles.sh
. Die Pfade in diesem Beispiel sind relativ; hardware/interfaces kann ein temporäres Verzeichnis unter Ihrem Codebaum sein, damit Sie eine HAL entwickeln können, bevor Sie sie veröffentlichen.
Ausführen eines Dienstes
Die HAL stellt die IFoo
-Schnittstelle bereit, die über die IFooCallback
-Schnittstelle asynchrone Rückrufe an das Framework durchführen muss. Die IFooCallback
Schnittstelle ist nicht namentlich als erkennbarer Dienst registriert; stattdessen muss IFoo
eine Methode wie setFooCallback(IFooCallback x)
enthalten.
Um IFooCallback
von Version 1.0 des Pakets android.hardware.foo
, fügen android.hardware.foo-V1.0-java
zu Android.mk
. Der Code zum Ausführen des Dienstes lautet:
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);
Schnittstellenerweiterungen
Angenommen, ein bestimmter Dienst implementiert die IFoo
Schnittstelle auf allen Geräten, ist es möglich, dass der Dienst auf einem bestimmten Gerät zusätzliche Funktionen bereitstellt, die in der Schnittstellenerweiterung IBetterFoo
wie folgt implementiert sind:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
Aufrufender Code, der die erweiterte Schnittstelle kennt, kann die Java-Methode castFrom()
verwenden, um die Basisschnittstelle sicher in die erweiterte Schnittstelle umzuwandeln:
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. }