HIDL-Java

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 bereits viele solche Schnittstellen in Form von HAL - Schnittstellen, definiert als C - Header in definierten hardware/libhardware . HIDL ersetzt diese HAL - Schnittstellen mit einem stabilen, versioniert Schnittstellen, die entweder in Java sein kann (unten beschrieben) oder client- und serverseitige HIDL Schnittstellen in seine C ++ .

HIDL-Schnittstellen sollen hauptsächlich aus nativem Code verwendet werden, und daher konzentriert sich HIDL auf die automatische Generierung von effizientem Code in C++. Allerdings müssen HIDL-Schnittstellen auch für die Nutzung 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 das Erstellen, Registrieren und Verwenden von Diensten und erklären, 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 in Paket android.hardware.foo@1.0 , die als Dienstnamen registriert ist default und einen zusätzlichen Service mit dem benutzerdefinierten Dienstnamen second_impl .

Bibliotheken hinzufügen

Sie müssen Abhängigkeiten zur 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 einbinden, 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 über eine System- oder Anbieter-App verfügen, die auf Android 10 oder höher ausgerichtet ist, können Sie diese Bibliotheken statisch einschließen. Sie können auch (nur) HIDL Klassen von benutzerdefinierten JAR - Dateien auf dem Gerät mit stabiler Java - APIs installiert verwenden gemacht den vorhandenen verfügbar mit uses-library Mechanismus für System - Anwendungen. Letzterer Ansatz spart Platz auf dem Gerät. Weitere Einzelheiten finden Sie Implementieren von Java SDK - Bibliothek . Bei älteren Apps wird das alte Verhalten beibehalten.

Ab Android 10 sind auch "flache" Versionen dieser Bibliotheken verfügbar. Diese enthalten die fragliche Klasse, aber keine der abhängigen Klassen. Zum Beispiel android.hardware.foo-V1.0-java-shallow enthält Klassen im Paket foo, enthält aber keine Klassen in android.hidl.base-V1.0-java , die die Basisklasse aller HIDL enthalten Schnittstellen. Wenn Sie eine Bibliothek erstellen, für die bereits die Basisklassen der bevorzugten Schnittstelle als Abhängigkeit verfügbar sind, 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 (vorher wurden sie aufgrund des Delegate-First-Klassenladers von Android manchmal als versteckte API verwendet). Stattdessen haben sie sich zu einem neuen Namensraum mit bewegt jarjar und Apps , die diese (unbedingt priv - Anwendungen) verwenden müssen ihre eigene separate Kopien haben. Module auf dem Boot - Classpath HIDL verwenden , müssen die flachen verwenden Varianten dieser Java - Bibliotheken und hinzuzufügen jarjar_rules: ":framework-jarjar-rules" , um ihre Android.bp die Version dieser Bibliotheken zu verwenden , die im Boot - Classpath existiert.

Ändern Ihrer Java-Quelle

Es gibt nur eine Version ( @1.0 ) diesen Dienst, so Diesen Code ruft nur diese Version. Siehe Schnittstellenerweiterungen , wie mehrere verschiedene Versionen des Service zu handhaben .

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(…);

Erbringung 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 der Version 1.0 des android.hardware.foo Paket können Sie Ihre Schnittstelle in Java unter Verwendung der folgenden Schritte implementieren:

  1. Definieren Sie Ihre Schnittstelle in HIDL.
  2. Öffnen /tmp/android/hardware/foo/IFooCallback.java als Referenz.
  3. Erstellen Sie ein neues Modul für Ihre Java-Implementierung.
  4. Untersuchen Sie die abstrakte Klasse android.hardware.foo.V1_0.IFooCallback.Stub , dann schreiben Sie eine neue Klasse , sie zu verlängern und zu implementieren , die abstrakten Methoden.

Anzeigen automatisch generierter 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 , um das Verzeichnis /tmp/android/hardware/foo/1.0 . Für die Datei hardware/interfaces/foo/1.0/IFooCallback.hal erzeugt diese die Datei /tmp/android/hardware/foo/1.0/IFooCallback.java , die die Java - Schnittstelle kapselt, den Proxy - Code und die Stubs (beide Proxy und Stubs entsprechen der Schnittstelle).

-Lmakefile erzeugt die Regeln , die diesen Befehl zur Buildzeit laufen und lassen Sie einschließen android.hardware.foo-V1.0-java und Link gegen die entsprechenden Dateien. Ein Skript , das dies automatisch tut für ein Projekt voller Schnittstellen 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 vor der Veröffentlichung entwickeln können.

Ausführen eines Dienstes

Die HAL stellt die IFoo - Schnittstelle, die asynchrone Rückrufe Rahmen über das machen muss IFooCallback Schnittstelle. Die IFooCallback Schnittstelle wird nicht namentlich als Erkennbar registriert sind ; Stattdessen IFoo muß , ein Verfahren , wie beispielsweise enthalten setFooCallback(IFooCallback x) .

So richten Sie IFooCallback ab Version 1.0 des android.hardware.foo Paket, 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

Unter der Annahme einer bestimmten Dienst implementiert die IFoo Schnittstelle für alle Geräte, ist es möglich , dass auf einem bestimmten Gerät der Dienst zusätzliche Funktionen in der Schnittstellenerweiterung implementiert bieten könnte IBetterFoo , wie folgt:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Telefonvorwahl sich der erweiterte Schnittstelle kann die Verwendung castFrom() Java - Methode , um sicher die Basis - Schnittstelle auf die erweiterte Schnittstelle umgewandelt:

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.
}