W systemie Android 8.0 architektura systemu operacyjnego Android została przebudowana w celu zdefiniowania przejrzystych interfejsów pomiędzy platformą Android niezależną od urządzenia a kodem specyficznym dla urządzenia i dostawcy. Android zdefiniował już wiele takich interfejsów w postaci interfejsów HAL, zdefiniowanych jako nagłówki C w hardware/libhardware
. HIDL zastąpił te interfejsy HAL stabilnymi, wersjonowanymi interfejsami, które mogą być albo w Javie (opisane poniżej), albo być interfejsami HIDL po stronie klienta i serwera w C++ .
Interfejsy HIDL mają być używane głównie z kodu natywnego, dlatego 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 poziomu 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 korzystania z 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.
Będąc klientem
To jest przykład klienta interfejsu IFoo
w pakiecie android.hardware.foo@1.0
, który jest zarejestrowany jako default
nazwa usługi i usługa dodatkowa z niestandardową nazwą usługi second_impl
.
Dodawanie bibliotek
Jeśli chcesz z niej skorzystać, musisz dodać zależności do 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ż pobierasz zależności z tych bibliotek, możesz także użyć łączenia współdzielonego:
// 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 system lub aplikację dostawcy, która jest przeznaczona dla systemu Android 10 lub nowszego, możesz statycznie dołączyć te biblioteki. Możesz także używać (tylko) klas HIDL z niestandardowych plików JAR zainstalowanych na urządzeniu ze stabilnymi interfejsami API Java udostępnianymi przy użyciu istniejącego mechanizmu uses-library
dla aplikacji systemowych. To drugie podejście pozwala zaoszczędzić miejsce na urządzeniu. Aby uzyskać więcej informacji, zobacz Implementowanie biblioteki Java SDK . W przypadku starszych aplikacji stare zachowanie zostaje zachowane.
Począwszy od Androida 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
zawiera klasy w pakiecie foo, ale nie zawiera klas w android.hidl.base-V1.0-java
, który zawiera klasę bazową wszystkich HIDL interfejsy. Jeśli tworzysz bibliotekę, która ma już dostępne klasy bazowe preferowanego interfejsu jako zależność, możesz użyć następujących opcji:
// 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żerskie HIDL również nie są już dostępne w ścieżce klas rozruchowych dla aplikacji (poprzednio były czasami używane jako ukryte API ze względu na moduł ładujący klasy z delegatem w systemie Android). Zamiast tego zostały przeniesione do nowej przestrzeni nazw z jarjar
, a aplikacje korzystające z nich (koniecznie aplikacje prywatne) muszą mieć własne, osobne kopie. Moduły w ścieżce klas startowych używające HIDL muszą używać płytkich wariantów tych bibliotek Java i dodać jarjar_rules: ":framework-jarjar-rules"
do swojego Android.bp
, aby używać wersji tych bibliotek, która istnieje w ścieżce klas startowych.
Modyfikowanie źródła Java
Istnieje tylko jedna wersja ( @1.0
) tej usługi, więc ten kod pobiera tylko tę wersję. Zobacz rozszerzenia interfejsu , aby dowiedzieć się, jak obsługiwać wiele różnych wersji 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 frameworka w Javie może wymagać obsługi interfejsów w celu odbierania asynchronicznych wywołań zwrotnych z warstw HAL.
W przypadku interfejsu IFooCallback
w wersji 1.0 pakietu android.hardware.foo
możesz zaimplementować swój interfejs w Javie, wykonując następujące kroki:
- Zdefiniuj swój interfejs w HIDL.
- Otwórz plik
/tmp/android/hardware/foo/IFooCallback.java
jako plik referencyjny. - Utwórz nowy moduł dla swojej implementacji Java.
- Sprawdź klasę abstrakcyjną
android.hardware.foo.V1_0.IFooCallback.Stub
, a następnie napisz nową klasę, aby ją rozszerzyć i zaimplementować metody abstrakcyjne.
Przeglądanie plików wygenerowanych automatycznie
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
Te polecenia generują katalog /tmp/android/hardware/foo/1.0
. W przypadku pliku hardware/interfaces/foo/1.0/IFooCallback.hal
generuje to plik /tmp/android/hardware/foo/1.0/IFooCallback.java
, który zawiera interfejs Java, kod proxy i kody pośredniczące (oba proxy i kody pośredniczące są zgodne z interfejsem).
-Lmakefile
generuje reguły uruchamiające to polecenie w czasie kompilacji i umożliwia dołączenie android.hardware.foo-V1.0-java
i powiązanie z odpowiednimi plikami. Skrypt, który automatycznie to robi dla projektu pełnego interfejsów, można znaleźć pod adresem hardware/interfaces/update-makefiles.sh
. Ścieżki w tym przykładzie są względne; hardware/interfaces może być katalogiem tymczasowym w drzewie kodu, umożliwiającym opracowanie warstwy HAL przed jej opublikowaniem.
Prowadzenie usługi
HAL zapewnia interfejs IFoo
, który musi wykonywać asynchroniczne wywołania zwrotne do platformy za pośrednictwem interfejsu IFooCallback
. Interfejs IFooCallback
nie jest zarejestrowany z nazwy jako usługa możliwa do wykrycia; zamiast tego IFoo
musi zawierać metodę taką jak setFooCallback(IFooCallback x)
.
Aby skonfigurować IFooCallback
z wersji 1.0 pakietu android.hardware.foo
, dodaj 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 usługa implementuje interfejs IFoo
na wszystkich urządzeniach, możliwe jest, że na konkretnym urządzeniu usługa może udostępnić dodatkowe możliwości zaimplementowane w rozszerzeniu interfejsu IBetterFoo
w następujący sposób:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
Wywołanie kodu obsługującego rozszerzony interfejs może wykorzystać metodę Java castFrom()
w celu bezpiecznego rzutowania interfejsu podstawowego na interfejs rozszerzony:
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. }