Android 10 obsługuje stabilny interfejs Androida Język definiowania (AIDL) – nowy sposób śledzenia programu aplikacji interfejs (API) i interfejs binarny aplikacji (ABI) dostarczane przez AIDL; i interfejsów. Stabilna wersja AIDL działa dokładnie tak samo jak AIDL, ale system kompilacji śledzi zgodność interfejsu. Istnieją też ograniczenia dotyczące czynności, które można wykonać:
- Interfejsy są zdefiniowane w systemie kompilacji za pomocą
aidl_interfaces
. - Interfejsy mogą zawierać tylko uporządkowane dane. Interfejs Parcelables reprezentujący preferowane typy są tworzone automatycznie na podstawie ich definicji AIDL i są automatycznie usuwane i usuwane z sieci.
- Interfejsy mogą być zadeklarowane jako stabilne (zgodne wstecznie). Gdy to interfejs API jest śledzony i umieszczany w pliku obok identyfikatora AIDL. za pomocą prostego interfejsu online.
Uporządkowane a stabilne AIDL
Uporządkowane AIDL odnosi się do typów zdefiniowanych wyłącznie w AIDL. Na przykład plik deklaracja parcelable (prywatna działka niestandardowa) nie ma struktury AIDL. Parcelables z ich polami zdefiniowanymi w AIDL są nazywane elementami strukturalnymi.
Stabilna AIDL wymaga uporządkowanych danych AIDL, tak aby system kompilacji i kompilator
może sprawdzić, czy zmiany wprowadzone w pakiecie są zgodne wstecznie.
Jednak nie wszystkie uporządkowane interfejsy są stabilne. Aby wszystko było stabilne,
interfejs może używać wyłącznie uporządkowanych typów oraz musi zawierać następujące
funkcje obsługi wersji. Interfejs jest niestabilny, jeśli główna kompilacja
do jego skompilowania lub ustawienia unstable:true
.
Definiowanie interfejsu AIDL
Definicja słowa aidl_interface
wygląda tak:
aidl_interface {
name: "my-aidl",
srcs: ["srcs/aidl/**/*.aidl"],
local_include_dir: "srcs/aidl",
imports: ["other-aidl"],
versions_with_info: [
{
version: "1",
imports: ["other-aidl-V1"],
},
{
version: "2",
imports: ["other-aidl-V3"],
}
],
stability: "vintf",
backend: {
java: {
enabled: true,
platform_apis: true,
},
cpp: {
enabled: true,
},
ndk: {
enabled: true,
},
rust: {
enabled: true,
},
},
}
name
: nazwa modułu interfejsu AIDL, który jednoznacznie identyfikuje Interfejs AIDL.srcs
: lista plików źródłowych AIDL, które składają się na interfejs. Ścieżka dla typu AIDLFoo
zdefiniowanego w pakieciecom.acme
powinna mieć wartość<base_path>/com/acme/Foo.aidl
, gdzie<base_path>
może być dowolnym katalogiem powiązane z katalogiem, w którym znajduje sięAndroid.bp
. W poprzednim przykładzie<base_path>
–srcs/aidl
.local_include_dir
: ścieżka, od której zaczyna się nazwa pakietu. it odpowiada<base_path>
wyjaśnionemu powyżej.imports
: lista modułówaidl_interface
używanych w tym module. Jeśli jedno z Twoich Interfejsy AIDL używają interfejsu lub pakietu Parcelableaidl_interface
, wpisz tutaj jej nazwę. Może to być sama nazwa, aby powołać się na lub nazwa z sufiksem wersji (np.-V1
), by się odwołać konkretnej wersji. Określanie wersji jest obsługiwane od Androida 12versions
: poprzednie wersje interfejsu, które są konto zablokowane w okresieapi_dir
, począwszy od Androida 11,versions
są zablokowane w przypadku licencjiaidl_api/name
. Jeśli nie ma zablokowanych wersji interfejsu, tego parametru nie należy określać i nie będzie przeprowadzana weryfikacja zgodności. W przypadku Androida to pole zostało zastąpione polemversions_with_info
13 lub więcej.versions_with_info
: lista krotek, z których każda zawiera nazwę zablokowana wersja i lista importów wersji innego interfejsu aidl_interface które zostały zaimportowane z tej wersji interfejsu aidl_interface. Definicja wersji V IFACE interfejsu AIDL znajduje się pod adresemaidl_api/IFACE/V
To pole wprowadziliśmy w Androidzie 13, i nie należy go modyfikować bezpośrednio wAndroid.bp
. To pole jest dodane lub zaktualizowane przez wywołanie metody*-update-api
lub*-freeze-api
. Oprócz tego polaversions
są automatycznie przenoszone doversions_with_info
. gdy użytkownik wywoła metodę*-update-api
lub*-freeze-api
.stability
: opcjonalna flaga obietnicy stabilności interfejsu. Ta funkcja obsługuje tylko"vintf"
. Jeśli zasadastability
nie jest skonfigurowana, kompilacja sprawdza, czy interfejs jest zgodny wstecznie, chyba że Podanounstable
. Gdy to ustawienie jest nieskonfigurowane, odpowiada interfejsowi stabilności w tym kontekście kompilacji (a więc zarówno wszystkie elementy systemu, na przykład rzeczy w elemenciesystem.img
i powiązane partycje lub we wszystkich dostawcach na przykład elementy w tabelivendor.img
i powiązane partycje). Jeślistability
ma wartość"vintf"
. Odpowiada to obietnicy stabilności: interfejs musi być stabilny, dopóki jest używany.gen_trace
: opcjonalna flaga do włączania i wyłączania śledzenia. Zaczyna się za Android 14 jest domyślnie ustawiony natrue
w przypadku aplikacjicpp
orazjava
backendów.host_supported
: opcjonalna flaga, która po ustawieniu natrue
powoduje, że z wygenerowanymi bibliotekami dostępnymi dla środowiska hosta.unstable
: opcjonalna flaga służąca do oznaczenia, że ten interfejs nie zezwala muszą być stabilne. Gdy zasada ma wartośćtrue
, system kompilacji nie tworzy zrzut API dla interfejsu ani nie wymaga jego aktualizacji.frozen
: opcjonalna flaga informująca o tym, że ustawienietrue
oznacza, że interfejs Nie wprowadziliśmy żadnych zmian od poprzedniej wersji interfejsu. Dzięki temu więcej kontroli w czasie kompilacji. Ustawienie wartościfalse
oznacza, że interfejs jest włączony. i ma nowe zmiany, dlatego uruchomienie poleceniafoo-freeze-api
generuje nowej wersji i automatycznie zmień wartość natrue
. Wprowadzona w grze Android 14.backend.<type>.enabled
: te flagi przełączają każdy z backendów kompilator AIDL generuje kod. Cztery backendy obsługiwane: Java, C++, NDK i Rust. Backendy Java, C++ i NDK są włączone domyślnie. Jeśli którykolwiek z tych 3 backendów nie jest potrzebny, wyłączono jawnie. System Rust jest domyślnie wyłączony do czasu Androida 15.backend.<type>.apex_available
: lista nazw APEX wygenerowanych przez dla których dostępna jest biblioteka stub.backend.[cpp|java].gen_log
: opcjonalna flaga określająca, czy wygenerować dodatkowy kod do gromadzenia informacji o transakcji.backend.[cpp|java].vndk.enabled
: opcjonalna flaga do tworzenia tego interfejsu. stanowią część VNDK. Wartość domyślna tofalse
.backend.[cpp|ndk].additional_shared_libraries
: wprowadzono w Androida 14, ta flaga dodaje zależności do bibliotek natywnych. Ta flaga jest przydatna w przypadkundk_header
icpp_header
.backend.java.sdk_version
: opcjonalna flaga do określania wersji. pakietu SDK, na podstawie którego została utworzona biblioteka Javy. Wartość domyślna to"system_current"
To ustawienie nie powinno być ustawione, gdybackend.java.platform_apis
jesttrue
.backend.java.platform_apis
: opcjonalna flaga, która powinna być ustawiona natrue
, gdy wygenerowane biblioteki muszą korzystać z interfejsu API platformy. a nie SDK.
Dla każdej kombinacji wersji i włączonych backendów dostępny jest po utworzeniu biblioteki. Jak odwołać się do konkretnej wersji biblioteki namiotowej dla konkretnego backendu, zapoznaj się z regułami nazewnictwa modułów.
Zapisywanie plików AIDL
Interfejsy w stabilnej wersji AIDL są podobne do interfejsów tradycyjnych, z wyjątkiem tego, że nie mogą używać obiektów nieuporządkowanych (ponieważ Nie są one stabilne. zobacz Uporządkowany a stabilny AIDL). Podstawową różnicą w stabilnej wersji AIDL jest to, Parcelables są zdefiniowane. Wcześniej pola parcelable były zadeklarowane. cale stabilnej (a więc uporządkowanej) AIDL, pola i zmienne Parcelables są w sposób jednoznaczny.
// in a file like 'some/package/Thing.aidl'
package some.package;
parcelable SubThing {
String a = "foo";
int b;
}
Wartości domyślne są obsługiwane (ale nie wymagane) dla tych atrybutów: boolean
, char
,
float
, double
, byte
, int
, long
i String
. Na Androidzie
12, wartości domyślne dla wyliczeń definiowanych przez użytkownika są również
obsługiwane. Jeśli wartość domyślna nie jest określona, używana jest wartość podobna do 0 lub pusta.
Wyliczenia bez wartości domyślnej są zainicjowane na 0, nawet jeśli
zero wyliczającego.
Korzystanie z bibliotek z stubami
Po dodaniu atrakcji do modułu jako zależności
możesz umieścić je w swoich plikach. Oto przykłady bibliotek pomocniczych w
system kompilacji (Android.mk
może być też używany do określania starszych definicji modułów):
cc_... {
name: ...,
shared_libs: ["my-module-name-cpp"],
...
}
# or
java_... {
name: ...,
// can also be shared_libs if your preference is to load a library and share
// it among multiple users or if you only need access to constants
static_libs: ["my-module-name-java"],
...
}
# or
rust_... {
name: ...,
rustlibs: ["my-module-name-rust"],
...
}
Przykład w C++:
#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
// use just like traditional AIDL
Przykład w Javie:
import some.package.IFoo;
import some.package.Thing;
...
// use just like traditional AIDL
Przykład w języku Rust:
use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
// use just like traditional AIDL
Interfejsy obsługi wersji
Zadeklarowanie modułu o nazwie foo powoduje też utworzenie celu w systemie kompilacji.
które mogą służyć do zarządzania interfejsem API w module. Po utworzeniu foo-freeze-api
dodaje nową definicję interfejsu API w sekcji api_dir
lub
aidl_api/name
w zależności od wersji Androida oraz
dodaje plik .hash
, które reprezentują nowo zablokowaną wersję
za pomocą prostego interfejsu online. foo-freeze-api aktualizuje też właściwość versions_with_info
.
aby odzwierciedlić wersję dodatkową, a imports
dla wersji. Zasadniczo
Pole imports
w tabeli versions_with_info
zostało skopiowane z pola imports
. Ale
najnowsza wersja stabilna jest określona w imports
w versions_with_info
dla
które nie ma jednoznacznej wersji.
Po określeniu właściwości versions_with_info
uruchamia się system kompilacji.
testy zgodności zablokowanych wersji oraz między wierzchołkiem drzewa (ToT)
oraz najnowszą zamrożoną wersję.
Musisz też zarządzać definicją interfejsu API wersji ToT. Za każdym razem, gdy interfejs API jest
zaktualizowany, uruchom foo-update-api, aby zaktualizować
aidl_api/name/current
który zawiera definicję interfejsu API wersji ToT.
Aby utrzymać stabilność interfejsu, właściciele mogą dodawać nowe:
- Metody umieszczone na końcu interfejsu (lub metody ze jawnie zdefiniowanymi nowymi numery seryjne)
- elementy na końcu pakietu (wymaga domyślnego dodania do każdego obiektu) ).
- Wartości stałe
- W Androidzie 11 liczniki
- W Androidzie 12 pola do końca sumy
Żadne inne działania nie są dozwolone ani nikt inny nie może modyfikować interfejsu (w przeciwnym razie istnieje ryzyko kolizji ze zmianami wprowadzonymi przez właściciela).
Aby sprawdzić, czy wszystkie interfejsy są zablokowane w wersji produkcyjnej, możesz kompilować następujący zestaw zmiennych środowiskowych:
AIDL_FROZEN_REL=true m ...
– kompilacja wymaga wszystkich stabilnych interfejsów AIDL zablokowane, które nie mają określonego polaowner:
.AIDL_FROZEN_OWNERS="aosp test"
– kompilacja wymaga wszystkich stabilnych interfejsów AIDL do zablokowania z polemowner:
określonym jako „aosp” czy „test”.
Stabilność importu
Aktualizowanie wersji importów zablokowanych wersji interfejsu jest kompatybilności wstecznej w warstwie stabilnej AIDL. Jednak ich aktualizacja wymaga aktualizowanie wszystkich serwerów i klientów korzystających z poprzedniej wersji interfejsu, a niektóre aplikacje mogą być zdezorientowane, gdy mieszamy różne wersje danego typu. Zasadniczo w przypadku typowych lub przeznaczonych tylko typów pakietów jest to bezpieczne, ponieważ kod musi już zapisane w celu obsługi nieznanych typów z transakcji IPC.
Na platformie Android kod android.hardware.graphics.common
jest największym
przykład uaktualnienia wersji.
Używaj interfejsów z różnymi wersjami interfejsu
Metody interfejsu
W trakcie działania przy próbie wywołania nowych metod na starym serwerze nowe klienty otrzymują może to być błąd lub wyjątek, w zależności od backendu.
- Backend
cpp
otrzymuje::android::UNKNOWN_TRANSACTION
. - Backend
ndk
otrzymujeSTATUS_UNKNOWN_TRANSACTION
. - Backend
java
otrzymujeandroid.os.RemoteException
z komunikatem o treści Interfejs API nie został zaimplementowany.
Aby dowiedzieć się, jak sobie z tym poradzić, zobacz wersje zapytań przy użyciu ustawień domyślnych.
Parcelables
Gdy do plików parcelable są dodawane nowe pola, stare klienty i serwery pomijają je. Gdy nowe klienty i serwery otrzymują stare pakiety parcels, domyślne wartości dla nowych są wypełniane automatycznie. Oznacza to, że wartości domyślne muszą być określony dla wszystkich nowych pól w pakiecie.
Klienci nie powinni oczekiwać, że serwery będą używać nowych pól, jeśli nie znają serwer implementuje wersję, która ma zdefiniowane pole (patrz wersje zapytań).
Wyliczenia i stałe
Klienty i serwery powinny odrzucać lub ignorować nierozpoznane stałych wartości i wyliczaczy, ponieważ więcej można dodać przyszłości. Na przykład serwer nie powinien przerywać działania po otrzymaniu żądania jest to coś, o czym nie wie. Serwer powinien albo zignorować parametr wyliczacza, ani zwrócić elementu, tak aby klient wiedział, że nie jest on obsługiwany w tej implementacji.
Związki
Próba wysłania sumy z nowym polem kończy się niepowodzeniem, jeśli odbiorca jest stary i
nie wie o tym polu. Implementacja nigdy nie wykryje połączenia z
nowe pole. Niepowodzenie jest ignorowane, jeśli
transakcja w jedną stronę, w przeciwnym razie błąd to BAD_VALUE
(dla języka C++ lub NDK
backend) lub IllegalArgumentException
(w przypadku backendu Javy). Błąd:
odbierany, jeśli klient wysyła wartość sumaryczną ustawioną na nowe pole na stare
lub gdy jest to stary klient odbierający połączenie z nowego serwera.
Zarządzanie wieloma wersjami
Przestrzeń nazw tagu łączącego na Androidzie może mieć tylko 1 wersję określonej aidl
w interfejsie, by uniknąć sytuacji, w których wygenerowane typy aidl
mają wiele
definicji. C++ ma regułę jednej definicji, która wymaga tylko jednej definicji
każdego symbolu.
Kompilacja Androida powoduje błąd, gdy moduł zależy od różnych wartości.
wersji tej samej biblioteki aidl_interface
. Moduł może zależeć od
bezpośrednio lub pośrednio przez zależności
zależności. Błędy te przedstawiają wykres zależności z modułu
kolidujących wersji biblioteki aidl_interface
. Wszystkie
trzeba zaktualizować zależności, aby uwzględnić tę samą (zwykle najnowszą)
tych bibliotek.
Jeżeli biblioteka interfejsu jest wykorzystywana przez wiele różnych modułów, pomocna może być
aby utworzyć cc_defaults
, java_defaults
i rust_defaults
dla dowolnej grupy
bibliotek i procesów, które muszą korzystać z tej samej wersji. Wprowadzając
nowej wersji interfejsu. Można aktualizować te wartości domyślne, a wszystkie moduły
są aktualizowane razem, dzięki czemu nie korzystają z różnych wersji
interfejsu.
cc_defaults {
name: "my.aidl.my-process-group-ndk-shared",
shared_libs: ["my.aidl-V3-ndk"],
...
}
cc_library {
name: "foo",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
cc_binary {
name: "bar",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
Gdy moduły aidl_interface
zaimportują inne moduły aidl_interface
, powstaną
dodatkowe zależności, które wymagają jednoczesnego użycia konkretnych wersji. Ten
może być trudna do zarządzania w przypadku powszechnych aidl_interface
zaimportowane do kilku używanych modułów aidl_interface
w ramach tych samych procesów.
aidl_interfaces_defaults
może posłużyć do zachowania jednej definicji
najnowsze wersje zależności obiektu „aidl_interface
”, które można zaktualizować w
w jednym miejscu. Są one używane przez wszystkie moduły aidl_interface
, które chcą zaimportować
taki wspólny interfejs.
aidl_interface_defaults {
name: "android.popular.common-latest-defaults",
imports: ["android.popular.common-V3"],
...
}
aidl_interface {
name: "android.foo",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
aidl_interface {
name: "android.bar",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
Programowanie oparte na flagach
Na urządzeniach w wersji produkcyjnej nie można używać interfejsów w wersji rozwojowej (niezablokowanej), ponieważ nie ma gwarancji zgodności wstecznej.
AIDL obsługuje kreacje zastępcze czasu działania dla tych niezablokowanych bibliotek interfejsu w kolejności , aby kod był pisany w najnowszej niezablokowanej wersji i nadal był używany na urządzeniach z włączoną wersją. Zachowanie zgodności wstecznej klientów jest podobne do i w przypadku kreacji zastępczych implementacje też muszą być takich zachowań. Zobacz Używanie interfejsów z obsługą różnych wersji.
Flaga kompilacji AIDL
Flaga tego działania to RELEASE_AIDL_USE_UNFROZEN
zdefiniowane w: build/release/build_flags.bzl
. true
oznacza niezablokowaną wersję
interfejs jest używany w czasie działania, a false
oznacza biblioteki bibliotek
wszystkie niezablokowane wersje zachowują się tak samo jak ostatnio zablokowane.
Możesz zmienić flagę na true
w przypadku
programistyczny, ale musi przywrócić go do wersji false
przed opublikowaniem. Zwykle
Programowanie odbywa się przy użyciu konfiguracji, która ma flagę ustawioną na true
.
Macierz zgodności i pliki manifestu
Obiekty interfejsu dostawcy (obiekty VINTF) – definicję które wersje powinny być poprawne, a jakie wersje po obu stronach za pomocą interfejsu dostawcy.
Większość urządzeń innych niż mątwy jest kierowana na najnowszą tablicę zgodności
dopiero po zamrożeniu interfejsów, więc nie ma różnicy w AIDL
biblioteki na podstawie RELEASE_AIDL_USE_UNFROZEN
.
Macierze
Interfejsy należące do partnera są dodawane do interfejsów, które są związane z konkretnym urządzeniem lub usługą.
lub macierzy zgodności, na które urządzenie jest kierowane w trakcie programowania. Kiedy więc
do macierzy zgodności jest dodawana nowa, niezablokowana wersja interfejsu,
poprzednio zablokowane wersje muszą być dostępne przez
RELEASE_AIDL_USE_UNFROZEN=false
Możesz sobie z tym poradzić, stosując różne
pliki macierzy zgodności dla różnych RELEASE_AIDL_USE_UNFROZEN
konfiguracji lub zezwolenie na obie wersje w jednym pliku macierzy zgodności
która jest używana we wszystkich konfiguracjach.
Na przykład podczas dodawania niezablokowanej wersji 4 użyj <version>3-4</version>
.
Gdy wersja 4 jest zablokowana, możesz usunąć wersję 3 z tablicy zgodności
ponieważ jest używana zablokowana wersja 4, gdy RELEASE_AIDL_USE_UNFROZEN
false
Pliki manifestu
W Androidzie 15 wprowadziliśmy zmianę w libvintf
:
modyfikować pliki manifestu w czasie kompilacji na podstawie wartości atrybutu
RELEASE_AIDL_USE_UNFROZEN
Pliki manifestu i fragmenty pliku manifestu określają wersję interfejsu
implementowana przez usługę. Jeśli korzystasz z najnowszej niezablokowanej wersji interfejsu,
Musisz zaktualizować plik manifestu, aby odzwierciedlał tę nową wersję. Kiedy
RELEASE_AIDL_USE_UNFROZEN=false
wpisy w pliku manifestu są dostosowywane według:
libvintf
, aby odzwierciedlić zmianę w wygenerowanej bibliotece AIDL. Wersja
została zmodyfikowana z niezablokowanej wersji (N
) na
ostatnio zamrożoną wersję N - 1
. Dzięki temu użytkownicy nie muszą zarządzać wieloma
pliki manifestu lub fragmenty plików manifestu dla poszczególnych usług.
Zmiany klienta HAL
Kod klienta HAL musi być zgodny wstecznie z każdym wcześniej obsługiwanym zablokowanym kodem klienta
wersji. Gdy RELEASE_AIDL_USE_UNFROZEN
ma wartość false
, usługi są zawsze sprawdzane
jak ostatnia zamrożona wersja lub wcześniej (na przykład wywołanie nowego niezablokowanego
zwraca wartość UNKNOWN_TRANSACTION
lub nowe pola parcelable
mają swoje wartości
wartości domyślne). Klienty platformy Android muszą działać wstecz
zgodne z dodatkowymi poprzednimi wersjami. Jest to jednak nowy szczegół
klientów dostawców i klientów korzystających z interfejsów należących do partnerów.
Zmiany w implementacji HAL
Największą różnicą w programowaniu HAL w przypadku programowania opartego na flagach jest
wymaga, aby implementacje HAL były zgodne wstecznie z ostatnimi
zablokowana wersja do działania, gdy RELEASE_AIDL_USE_UNFROZEN
ma wartość false
.
Uwzględnienie zgodności wstecznej w implementacjach i kodzie urządzenia to nowość.
ćwiczenia. Zobacz Używanie obsługi wersji
.
Uwagi na temat zgodności wstecznej są zasadniczo takie same w przypadku dla klientów i serwerów, kodu platformy i kodu dostawcy. subtelne różnice, o których należy pamiętać, zaimplementowanie dwóch wersji, które korzystają z tego samego kodu źródłowego (obecnej, niezablokowanej wersji).
Przykład: interfejs ma 3 zablokowane wersje. Interfejs został zaktualizowany o
nowej metody. Klient i usługa zostaną zaktualizowane tak, aby korzystały z nowej wersji 4.
bibliotece. Ponieważ biblioteka V4 opiera się na niezablokowanej wersji biblioteki
działa jak ostatnia zablokowana wersja (wersja 3),
Metoda RELEASE_AIDL_USE_UNFROZEN
ma wartość false
i uniemożliwia użycie nowej metody.
Gdy interfejs jest zablokowany, wszystkie wartości RELEASE_AIDL_USE_UNFROZEN
używają tego
zamrożoną wersję, a kod obsługujący zgodność wsteczną może zostać usunięty.
Gdy wywołujesz metody z wywołaniami zwrotnymi, musisz płynnie obsługiwać
Zwracana jest wartość UNKNOWN_TRANSACTION
. Klienci mogą wdrażać 2 różne
na podstawie konfiguracji wersji. Nie możesz więc
przy założeniu, że klient wysyła najnowszą wersję, a nowe metody mogą zwrócić
to osiągnąć. Jest to podobne do tego, jak stabilne są stabilne klienty AIDL w tle
zgodność z serwerami opisanymi w artykule Używanie obsługi wersji
.
// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
mMyCallback = cb;
// Get the version of the callback for later when we call methods on it
auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
return status;
}
// Example of using the callback later
void NotifyCallbackLater() {
// From the latest frozen version (V2)
mMyCallback->foo();
// Call this method from the unfrozen V3 only if the callback is at least V3
if (mMyCallbackVersion >= 3) {
mMyCallback->bar();
}
}
Nowe pola w istniejących typach (parcelable
, enum
, union
) mogą
nie istnieje lub nie zawierają swoich wartości domyślnych, gdy RELEASE_AIDL_USE_UNFROZEN
jest
Pola false
i wartości nowych pól, które próbuje wysłać usługa, są usuwane
jest dla nas nie do przyjęcia.
Nie można wysyłać nowych typów dodanych do tej niezablokowanej wersji lub odebrany jej za pomocą interfejsu.
Implementacja nigdy nie żąda nowych metod od żadnego klienta,
Obecny stan „RELEASE_AIDL_USE_UNFROZEN
”: false
.
Pamiętaj, aby używać nowych modułów wyliczających tylko w wersji, w której zostały wprowadzone, a nie w poprzedniej wersji.
Zwykle do sprawdzania wersji pilota służy foo->getInterfaceVersion()
przez interfejs API. Jednak dzięki obsłudze wersji opartej na flagach
implementacji dwóch różnych wersji, warto więc pobrać wersję
do bieżącego interfejsu. Aby to zrobić, pobierz wersję interfejsu
bieżący obiekt, na przykład this->getInterfaceVersion()
lub inny
dla metody my_ver
. Patrz: Wysyłanie zapytań o wersję interfejsu pilota
.
Nowe stabilne interfejsy VINTF
Po dodaniu nowego pakietu interfejsu AIDL nie ma ostatniej zablokowanej wersji, więc
nie ma żadnego działania, do którego można wrócić, gdy RELEASE_AIDL_USE_UNFROZEN
to
false
Nie używaj tych interfejsów. Gdy RELEASE_AIDL_USE_UNFROZEN
to
false
, menedżer usług nie zezwala usłudze na zarejestrowanie interfejsu
i klienci ich nie znajdą.
Możesz dodawać usługi warunkowo, bazując na wartości atrybutu
Flaga RELEASE_AIDL_USE_UNFROZEN
w pliku Makefile urządzenia:
ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
android.hardware.health.storage-service
endif
Jeśli usługa jest częścią większego procesu i nie można dodać jej na urządzeniu
warunkowo możesz sprawdzić, czy usługa jest zadeklarowana za pomocą argumentu
IServiceManager::isDeclared()
Jeśli jest zadeklarowana, ale nie udało się jej zarejestrować,
przerwać ten proces. Jeśli nie jest zadeklarowana, prawdopodobnie nie uda się jej zarejestrować.
Mątwa jako narzędzie dla programistów
Co roku po zamrożeniu zasad VINTF dostosowujemy zgodność platformy
macierz (FCM) target-level
i PRODUCT_SHIPPING_API_LEVEL
mątwy
więc odzwierciedlają one urządzenia
udostępniane w przyszłym roku. Dostosujemy
target-level
i PRODUCT_SHIPPING_API_LEVEL
, aby upewnić się, że zostały poprawnie
wprowadzić na rynek urządzenie, które zostało przetestowane i spełnia nowe wymagania na przyszły rok
wersji.
Gdy RELEASE_AIDL_USE_UNFROZEN
ma wartość true
, mątwy jest
służy do tworzenia przyszłych wersji Androida. Jest kierowana na Androida w przyszłym roku
na poziomie FCM wydania i w ustawieniu PRODUCT_SHIPPING_API_LEVEL
, co wymaga, aby spełniała
wymagania dotyczące oprogramowania dostawcy (VSR) kolejnej wersji.
Gdy RELEASE_AIDL_USE_UNFROZEN
to false
, mątwy ma poprzedni
target-level
i PRODUCT_SHIPPING_API_LEVEL
, aby uwzględnić urządzenie, na którym wydano produkt.
W Androidzie 14 i starszych wersjach
w różnych gałęziach Git, które nie przyjmują zmiany w FCM.
target-level
, poziom interfejsu API dostawy lub dowolny inny kod kierowany na następny
wersji.
Reguły nazewnictwa modułów
W Androidzie 11 dla każdej kombinacji wersji
Gdy backendy są włączone, moduł biblioteki skróconej jest tworzony automatycznie. Aby polecić
do określonego modułu biblioteki skróconej w celu połączenia, nie używaj nazwy modułu
aidl_interface
ale nazwa modułu biblioteki skróconej, która jest
ifacename-version-backend, gdzie
ifacename
: nazwa modułuaidl_interface
version
należy do jednego zVversion-number
dla zablokowanych wersjiVlatest-frozen-version-number + 1
dla wersja na wierzchu drzewa (jeszcze do zamrożenia)
backend
należy do jednego zjava
dla backendu Javy,cpp
dla backendu C++,ndk
lubndk_platform
dla backendu NDK. Pierwsza dotyczy aplikacji, a drugie – do korzystania z platformy do czasu wprowadzenia Androida 13. W Android 13 i nowsze korzystają tylko zndk
.rust
dla backendu Rust.
Załóżmy, że istnieje moduł o nazwie foo, a jego najnowsza wersja to 2, i obsługuje zarówno NDK, jak i C++. W takim przypadku AIDL generuje te moduły:
- Na podstawie wersji 1
foo-V1-(java|cpp|ndk|ndk_platform|rust)
- Na podstawie wersji 2 (najnowszej stabilnej)
foo-V2-(java|cpp|ndk|ndk_platform|rust)
- Na podstawie wersji Warunków korzystania z usługi
foo-V3-(java|cpp|ndk|ndk_platform|rust)
W porównaniu z Androidem 11:
foo-backend
, który odwołuje się do najnowszej stabilnej wersji wersja zmieni się nafoo-V2-backend
foo-unstable-backend
, który odwołuje się do Warunków korzystania z usługi wersja zmieni się nafoo-V3-backend
Nazwy plików wyjściowych są zawsze takie same jak nazwy modułów.
- Na podstawie wersji 1:
foo-V1-(cpp|ndk|ndk_platform|rust).so
- Na podstawie wersji 2:
foo-V2-(cpp|ndk|ndk_platform|rust).so
- Na podstawie wersji Warunków korzystania z usługi:
foo-V3-(cpp|ndk|ndk_platform|rust).so
Pamiętaj, że kompilator AIDL nie tworzy ani modułu wersji unstable
,
albo moduł bez wersji dla stabilnego interfejsu AIDL.
Od Androida 12 nazwa modułu jest generowana na podstawie
stabilny interfejs AIDL zawsze zawiera jego wersję.
Nowe metody interfejsu meta
Android 10 dodaje kilka metod metainterfejsu stabilnej wersji AIDL.
Wyślij zapytanie do wersji interfejsu obiektu zdalnego
Klienty mogą wysyłać zapytania o wersję i hasz interfejsu wskazywany przez obiekt zdalny implementuje i porównuje zwrócone wartości z wartościami podanymi w interfejsie używanych przez klienta.
Przykład z backendem cpp
:
sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
// the remote side is using an older interface
}
std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();
Przykład z backendem ndk
(i ndk_platform
):
IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
// the remote side is using an older interface
}
std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);
Przykład z backendem java
:
IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
// the remote side is using an older interface
}
String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();
W przypadku języka Java strona zdalna MUSI obsługiwać zmienne getInterfaceVersion()
i
getInterfaceHash()
w następujący sposób (super
zamiast IFoo
jest używany, aby uniknąć
przy kopiowaniu i wklejaniu błędów. Adnotacja @SuppressWarnings("static")
może
może być konieczne wyłączenie ostrzeżeń, zależnie od konfiguracji javac
):
class MyFoo extends IFoo.Stub {
@Override
public final int getInterfaceVersion() { return super.VERSION; }
@Override
public final String getInterfaceHash() { return super.HASH; }
}
Wynika to z faktu, że wygenerowane zajęcia (IFoo
, IFoo.Stub
itp.) są udostępniane
między klientem a serwerem (na przykład klasy mogą znajdować się w rozruchu
classpath). Podczas udostępniania zajęć serwer jest też powiązany z
najnowszą wersję zajęć, nawet jeśli zostały utworzone przy użyciu starszej wersji;
wersji interfejsu. Jeśli ten metainterfejs jest zaimplementowany w
klasa, zawsze zwraca najnowszą wersję. Jeśli jednak zastosujesz metodę
jak powyżej, numer wersji interfejsu jest osadzony w kodzie serwera
(ponieważ IFoo.VERSION
to static final int
, który jest wbudowany, gdy się odwołuje)
więc ta metoda może zwrócić dokładnie tę wersję serwera,
Radzenie sobie ze starszymi interfejsami
Możliwe, że klient został zaktualizowany do nowszej wersji AIDL
ale serwer używa starego interfejsu AIDL. W takich przypadkach
wywołanie metody w starym interfejsie zwraca UNKNOWN_TRANSACTION
.
Stabilna wersja AIDL daje klientom większą kontrolę. Po stronie klienta możesz ustawić domyślną implementacją interfejsu AIDL. Metoda w wartości domyślnej jest wywoływane tylko wtedy, gdy metoda nie jest zaimplementowana na pilocie (ponieważ utworzono go przy użyciu starszej wersji interfejsu). Od są ustawiane globalnie, więc nie należy ich używać kontekstach.
Przykład w C++ na Androidzie 13 i nowszych:
class MyDefault : public IFooDefault {
Status anAddedMethod(...) {
// do something default
}
};
// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());
foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
// remote side is not implementing it
Przykład w Javie:
IFoo.Stub.setDefaultImpl(new IFoo.Default() {
@Override
public xxx anAddedMethod(...) throws RemoteException {
// do something default
}
}); // once per an interface in a process
foo.anAddedMethod(...);
Nie musisz podawać domyślnej implementacji wszystkich metod w AIDL
za pomocą prostego interfejsu online. Metody, które mają zagwarantowane wdrożenie na zdalnym serwerze
(ponieważ masz pewność, że pilot został stworzony, gdy metody były w
AIDL) nie trzeba zastępować w domyślnej wartości impl
.
zajęcia.
Przekonwertuj istniejące AIDL na uporządkowane lub stabilne AIDL
Jeśli masz już interfejs AIDL i kod, który z niego korzysta, skorzystaj z następującego konwersji interfejsu do stabilnego interfejsu AIDL.
Określ wszystkie zależności interfejsu. Dla każdego pakietu należy sprawdzić, czy pakiet jest zdefiniowany w stabilnej wersji AIDL. Jeśli nie zdefiniowano, należy przekonwertować pakiet.
Przekonwertuj wszystkie pakiety w interfejsie na pakiety stabilne ( same pliki interfejsu mogą pozostać niezmienione). Zrób to do oraz bezpośrednio w plikach AIDL. Zajęcia zarządzania muszą i zapisywać je od nowa, by używać ich nowych typów. Można to zrobić przed utworzeniem
aidl_interface
pakiet (poniżej).Utwórz pakiet
aidl_interface
(w sposób opisany powyżej), który zawiera nazwę modułu, jego zależności i wszelkie inne potrzebne informacje. Aby był stabilizowany (a nie tylko uporządkowany), trzeba też zmienić jego wersję. Więcej informacji znajdziesz w artykule na temat interfejsów wersji.