HIDL Java

W systemie Android 8.0 system operacyjny Android został przeprojektowany, aby zdefiniować przejrzyste interfejsy między platformą Android niezależną od urządzenia a kodem specyficznym dla urządzenia i dostawcy. Android już zdefiniowano wiele takich interfejsów w postaci interfejsu Hal, określonych jako nagłówki C w hardware/libhardware . HIDL wymienić te interfejsy HAL ze stabilnych wersjonowanymi interfejsów, które mogą być w Java (opisanych poniżej), lub być dla klientów, jak i po stronie serwera, w interfejsy HIDL C ++ .

Interfejsy HIDL mają być używane głównie z kodu natywnego, w wyniku czego HIDL koncentruje się na automatycznym generowaniu wydajnego kodu w C++. Jednak interfejsy HIDL muszą być również dostępne do użytku bezpośrednio z języka Java, ponieważ niektóre podsystemy Androida (takie jak Telefonia) mają interfejsy Java HIDL.

Strony w tej sekcji opisują interfejs Java dla interfejsów HIDL, szczegółowo opisują sposób tworzenia, rejestrowania i używania usług oraz wyjaśniają, w jaki sposób warstwy HAL i klienci HAL napisane w języku Java współdziałają z systemem HIDL RPC.

Bycie klientem

To jest przykład z klientem dla interfejsu IFoo w opakowaniu android.hardware.foo@1.0 która jest zarejestrowana jako nazwa usługi default i dodatkowe usługi z niestandardowej nazwy usługi second_impl .

Dodawanie bibliotek

Jeśli chcesz z niej korzystać, musisz dodać zależności od odpowiedniej biblioteki pośredniczącej HIDL. Zwykle jest to biblioteka statyczna:

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

Jeśli wiesz, że już ściągasz zależności od tych bibliotek, możesz również użyć współdzielonego powiązania:

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

Dodatkowe uwagi dotyczące dodawania bibliotek w systemie Android 10

Jeśli masz aplikację systemową lub dostawcę, która jest przeznaczona dla systemu Android 10 lub nowszego, możesz statycznie dołączyć te biblioteki. Można również użyć (tylko) z niestandardowych klas HIDL JAR zainstalowanych na urządzeniu z stabilnych Java API udostępniane z wykorzystaniem istniejących uses-library mechanizm aplikacji systemowych. To drugie podejście pozwala zaoszczędzić miejsce na urządzeniu. Aby uzyskać więcej informacji, zobacz wykonawcze Java SDK Library . W przypadku starszych aplikacji zachowywane jest stare zachowanie.

Począwszy od systemu Android 10, dostępne są również „płytkie” wersje tych bibliotek. Obejmują one daną klasę, ale nie obejmują żadnej z klas zależnych. Na przykład, android.hardware.foo-V1.0-java-shallow obejmuje zajęcia z pakietem foo, ale nie obejmuje zajęcia w android.hidl.base-V1.0-java , który zawiera klasę bazową wszystkich HIDL interfejsy. Jeśli tworzysz bibliotekę, która ma już klasy bazowe preferowanego interfejsu dostępne jako zależność, możesz użyć następującego:

// 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

Biblioteki podstawowe i menedżera HIDL nie są już dostępne w ścieżce klas rozruchowych dla aplikacji (wcześniej były one czasami używane jako ukryte API, ze względu na pierwszy ładowacz klas Androida). Zamiast tego, że zostały przeniesione do nowej przestrzeni nazw z jarjar i aplikacje, które wykorzystują te aplikacje (koniecznie priv) muszą posiadać własne oddzielne kopie. Moduły na ścieżce klasy startowego przy użyciu HIDL musi użyć płytkie warianty tych bibliotek Java i dodać jarjar_rules: ":framework-jarjar-rules" do ich Android.bp użyć wersji tych bibliotek, które istnieje w ścieżce klasy startowego.

Modyfikowanie źródła Java

Jest tylko jedna wersja ( @1.0 ) z tej usługi, więc ten kod pobiera tylko, że wersja. Zobacz interfejsu rozszerzeń dla jak obsługiwać wiele różnych wersji tej usługi.

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

Świadczenie usługi

Kod struktury w Javie może wymagać obsługi interfejsów w celu odbierania asynchronicznych wywołań zwrotnych z warstw HAL.

Dla IFooCallback interfejsu w wersji 1.0 android.hardware.foo pakietu, można zaimplementować interfejs w języku Java, wykonując następujące kroki:

  1. Zdefiniuj swój interfejs w HIDL.
  2. Otwarte /tmp/android/hardware/foo/IFooCallback.java jako odniesienie.
  3. Utwórz nowy moduł dla swojej implementacji Java.
  4. Zbadanie klasy abstrakcyjnej android.hardware.foo.V1_0.IFooCallback.Stub , a następnie napisać nową klasę do rozszerzenia go i wdrożenia metody abstrakcyjne.

Przeglądanie automatycznie wygenerowanych plików

Aby wyświetlić automatycznie wygenerowane pliki, uruchom:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0

Polecenia te generują katalogów /tmp/android/hardware/foo/1.0 . Dla plików hardware/interfaces/foo/1.0/IFooCallback.hal ta generuje pliku /tmp/android/hardware/foo/1.0/IFooCallback.java , który hermetyzuje interfejs Java, kod proxy, a odcinki (zarówno proxy i odgałęzienia są zgodne z interfejsem).

-Lmakefile generuje zasady, które działają tego polecenia w czasie kompilacji i pozwalają na to android.hardware.foo-V1.0-java oraz link przeciwko odpowiednich plików. Skrypt, który robi to automatycznie dla projektu pełnego interfejsów można znaleźć na hardware/interfaces/update-makefiles.sh . Ścieżki w tym przykładzie są względne; sprzęt/interfejsy mogą być tymczasowym katalogiem w drzewie kodu, aby umożliwić opracowanie warstwy HAL przed jej opublikowaniem.

Prowadzenie usługi

HAL zapewnia IFoo interfejs, który musi zrobić asynchronicznych wywołań zwrotnych do ram nad IFooCallback interfejsu. IFooCallback interfejs nie jest zarejestrowany wg nazwy jako wykrycie usługi; Zamiast IFoo musi zawierać metody, takiej jak setFooCallback(IFooCallback x) .

Aby skonfigurować IFooCallback od wersji 1.0 android.hardware.foo opakowaniu, dodać android.hardware.foo-V1.0-java do Android.mk . Kod do uruchomienia usługi to:

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

Rozszerzenia interfejsu

Zakładając, że dana wdraża usłudze IFoo interfejs we wszystkich urządzeniach, jest możliwe, że na określonym urządzeniu usługa może zapewnić dodatkowe funkcje zaimplementowane w rozszerzeniu interfejsu IBetterFoo , co następuje:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

Wywołanie kodu świadomi rozszerzonego interfejsu mogą korzystać z castFrom() metoda Java, aby bezpiecznie rzucać interfejs bazowy do rozszerzonego interfejsu:

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