AIDL obsługuje adnotacje, które dostarczają kompilatorowi AIDL dodatkowe informacje o elemencie z adnotacjami, co również ma wpływ na wygenerowany kod pośredni.
Składnia jest podobna do składni w Javie:
@AnnotationName(argument1=value, argument2=value) AidlEntity
AnnotationName
to nazwa adnotacji, a AidlEntity
to encja AIDL, np. interface Foo
, void method()
lub int arg
. Do encji, która następuje po nim, jest dołączona adnotacja.
Niektóre adnotacje mogą mieć argumenty w nawiasach, jak pokazano powyżej. Adnotacje, które nie mają argumentu, nie wymagają nawiasów. Na przykład:
@AnnotationName AidlEntity
Te adnotacje różnią się od adnotacji w języku Java, choć wyglądają bardzo podobnie. Użytkownicy nie mogą definiować własnych adnotacji AIDL. Wszystkie adnotacje są zdefiniowane wstępnie. Niektóre adnotacje mają zastosowanie tylko do określonego backendu i nie działają w innych backendach. Obowiązują różne ograniczenia, do których można je dołączyć.
Oto lista wstępnie zdefiniowanych adnotacji AIDL:
Adnotacje | Dodano w wersji na Androida |
---|---|
nullable |
7 |
utf8InCpp |
7 |
VintfStability |
11 |
UnsupportedAppUsage |
10 |
Hide |
11 |
Backing |
11 |
NdkOnlyStableParcelable |
14 |
JavaOnlyStableParcelable |
11 |
JavaDerive |
12 |
JavaPassthrough |
12 |
FixedSize |
12 |
Descriptor |
12 |
nullable
nullable
oznacza, że wartość opatrzonego adnotacją elementu może nie być podana.
Tę adnotację można dołączyć tylko do typów zwracanych przez metodę, parametrów metody i pól możliwych do podzielenia.
interface IFoo {
// method return types
@nullable Data method();
// method parameters
void method2(in @nullable Data d);
}
parcelable Data {
// parcelable fields
@nullable Data d;
}
Adnotacji nie można dołączać do typów podstawowych. Poniżej znajduje się błąd.
void method(in @nullable int a); // int is a primitive type
Ta adnotacja nie ma zastosowania w przypadku zaplecza w języku Java. Dzieje się tak, ponieważ w języku Java wszystkie typy inne niż prymitywne są przekazywane przez odniesienie, które może być null
.
W backendzie CPP identyfikator @nullable T
jest mapowany na std::unique_ptr<T>
w Androidzie 11 lub starszym oraz na std::optional<T>
w Androidzie 12 lub nowszym.
W backendzie NDK wartość @nullable T
zawsze jest mapowana na std::optional<T>
.
W backendzie Rust @nullable T
zawsze mapuje się na Option<T>
.
W przypadku typu L
, np. T[]
lub List<T>
, @nullable L
jest mapowane na std::optional<std::vector<std::optional<T>>>
(lub std::unique_ptr<std::vector<std::unique_ptr<T>>>
w przypadku backendu CPP w Androidzie 11 lub niższym).
W przypadku tego mapowania istnieje wyjątek. Gdy T
jest IBinder
lub interfejsem AIDL, @nullable
nie wykonuje żadnej operacji na żadnym backendzie oprócz Rust. Innymi słowy, zarówno @nullable IBinder
, jak i IBinder
mapują się na android::sp<IBinder>
, która jest już typu nullable, ponieważ jest to silny wskaźnik (w przypadku odczytu w C++ nadal obowiązuje zasada nullable, ale typ jest nadal android::sp<IBinder>
). W Rust te typy są nullable
tylko wtedy, gdy są opatrzone adnotacją @nullable
. Jeśli są opatrzone adnotacjami, są przypisane do Option<T>
.
Począwszy od Androida 13 możesz używać pola @nullable(heap=true)
do modelowania typów rekurencyjnych w przypadku pól parcelowalnych. @nullable(heap=true)
nie może być używana z parametrami metody ani typami zwracanymi. Gdy jest ono opatrzone adnotacjami, jest mapowane na odwołanie std::unique_ptr<T>
przydzielone na stosie w backendach CPP/NDK. Interfejs @nullable(heap=true)
nie działa w backendzie Java.
utf8InCpp
utf8InCpp
deklaruje, że String
jest reprezentowany w formacie UTF-8 na zapleczu CPP. Jak sama nazwa wskazuje, adnotacja nie jest operacją w innych backendach.
W szczególności String
jest zawsze w formacie UTF-16 w backendzie Java i w formacie UTF-8 w backendzie NDK.
Tę adnotację można dołączyć wszędzie tam, gdzie można użyć typu String
, w tym w wartościach zwracanych, parametrach, stałych deklaracjach i polach parcelable.
W przypadku backendu w C++ parametr @utf8InCpp String
w pliku AIDL jest mapowany na std::string
, natomiast parametr String
bez adnotacji jest mapowany na android::String16
, gdzie używany jest format UTF-16.
Pamiętaj, że obecność adnotacji utf8InCpp
nie zmienia sposobu przesyłania ciągów znaków przez sieć. Ciągi znaków są zawsze przesyłane w formacie UTF16. Przed przesłaniem ciąg znaków z adnotacjami utf8InCpp
jest konwertowany na UTF16. Gdy otrzymany ciąg znaków został oznaczony jako utf8InCpp
, jest on konwertowany z UTF16 na UTF8.
VintfStability
VintfStability
deklaruje, że typ zdefiniowany przez użytkownika (interface, parcelable, enum) może być używany w domenie systemu i dostawcy. Więcej informacji o interoperacyjności dostawców systemów znajdziesz w AIDL dla HAL-i.
Adnotacja nie zmienia sygnatury typu, ale po jej ustawieniu instancja typu jest oznaczana jako stabilna, aby mogła być przekazywana przez procesy dostawcy i systemu.
Adnotację można dołączyć tylko do deklaracji typu zdefiniowanego przez użytkownika, jak pokazano tutaj:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
Gdy typ jest opatrzony adnotacją VintfStability
, powinien być również opatrzony adnotacją do każdego innego typu, do którego odwołuje się typ. W tym przykładzie Data
i IBar
powinny być oznaczone jako VintfStability
.
@VintfStability
interface IFoo {
void doSomething(in IBar b); // references IBar
void doAnother(in Data d); // references Data
}
@VintfStability // required
interface IBar {...}
@VintfStability // required
parcelable Data {...}
Oprócz tego pliki AIDL definiujące typy z adnotacjami VintfStability
można tworzyć tylko za pomocą typu modułu aidl_interface
Soong z właściwością stability
ustawioną na "vintf"
.
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
Adnotacja UnsupportedAppUsage
oznacza, że oznaczony typ AIDL jest częścią interfejsu spoza pakietu SDK, który był dostępny dla starszych aplikacji.
Więcej informacji o ukrytych interfejsach API znajdziesz w artykule Ograniczenia dotyczące interfejsów API innych niż szkielety aplikacji.
Adnotacja UnsupportedAppUsage
nie ma wpływu na działanie wygenerowanego kodu. Adnotacja dotyczy tylko wygenerowanej klasy Java i ma taką samą nazwę.
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
To ustawienie nie jest dostępne dla backendów innych niż Java.
Podparcie
Adnotacja Backing
określa typ pamięci masowej dla typu enum AIDL.
@Backing(type="int")
enum Color { RED, BLUE, }
W backendzie CPP generuje to klasę typu int32_t
z enumeracją C++.
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
Jeśli pominiesz adnotację, zostanie domyślnie przyjęta wartość type
, która w przypadku backendu CPP jest mapowana na wartość int8_t
.byte
Argument type
można ustawić tylko na te typy całek:
byte
(8-bitowy)int
(32-bitowa szerokość)long
(64-bitowa szerokość)
NdkOnlyStableParcelable
NdkOnlyStableParcelable
oznacza deklarację parcelable (nie definicję) jako stabilną, aby można było się do niej odwoływać z innych stabilnych typów AIDL. Jest to podobne do JavaOnlyStableParcelable
, ale NdkOnlyStableParcelable
oznacza deklarację parcelable jako stabilną dla backendu NDK, a nie dla Javy.
Aby użyć tej funkcji:
- Musisz podać wartość
ndk_header
. - Musisz mieć bibliotekę NDK, która określa parcelable, i musisz ją skompilować w bibliotece. Na przykład w podstawowym systemie kompilacji modułu
cc_*
użyjstatic_libs
lubshared_libs
. W przypadkuaidl_interface
dodaj bibliotekę w sekcjiadditional_shared_libraries
wAndroid.bp
.
JavaOnlyStableParcelable,
JavaOnlyStableParcelable
oznacza deklarację parcelable (nie definicję) jako stabilną, aby można było się do niej odwoływać z innych stabilnych typów AIDL.
Stabilny interfejs AIDL wymaga, aby wszystkie typy zdefiniowane przez użytkownika były stabilne. Stabilność w przypadku pakietów SDK wymaga jawnego opisania pól w pliku źródłowym AIDL.
parcelable Data { // Data is a structured parcelable.
int x;
int y;
}
parcelable AnotherData { // AnotherData is also a structured parcelable
Data d; // OK, because Data is a structured parcelable
}
Jeśli obiekt Parcelable był nieustrukturyzowany (lub tylko zadeklarowany), nie można go odwoływać.
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable
pozwala zastąpić sprawdzenie, gdy referencje do obiektu Parcelable są już bezpiecznie dostępne w pakiecie SDK Androida.
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive
automatycznie generuje w backendzie Java metody dla typów papierowych.
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
Adnotacja wymaga dodatkowych parametrów określających, co ma być generowane. Obsługiwane parametry:
equals=true
generuje metodyequals
ihashCode
.toString=true
generuje metodętoString
, która wypisuje nazwę typu i pola. Na przykład:Data{number: 42, str: foo}
JavaDefault
JavaDefault
, dodana w Androidzie 13, określa, czy domyślna obsługa wersji implementacji (w przypadku setDefaultImpl
) jest generowana. Domyślnie nie jest już generowana, aby oszczędzać miejsce.
JavaPassthrough
JavaPassthrough
umożliwia dodanie do wygenerowanego interfejsu Java API adnotacji przy użyciu dowolnej adnotacji w języku Java.
te adnotacje w pliku AIDL:
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")
stać się
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
w wygenerowanym kodzie Java.
Wartość parametru annotation
jest emitowana bezpośrednio. Kompilator AIDL nie sprawdza wartości parametru. Jeśli wystąpi jakikolwiek błąd składni na poziomie Javy, nie zostanie on wykryty przez kompilator AIDL, ale przez kompilator Javy.
Tę adnotację można dołączyć do dowolnej jednostki AIDL. Ta adnotacja jest ignorowana w przypadku backendów innych niż Java.
Stały rozmiar
FixedSize
oznacza działkę strukturalną jako stały rozmiar. Po oznaczeniu nie można dodawać do niego nowych pól. Wszystkie pola obiektu parcelable muszą być typu o stałym rozmiarze, w tym typów prymitywnych, enumeracji, tablic o stałym rozmiarze i innych obiektów parcelable oznaczonych FixedSize
.
Nie zapewnia to żadnej gwarancji w przypadku różnych głębokości bitów i nie należy polegać na tym w przypadku komunikacji z różną głębią bitów.
Deskryptor
Descriptor
nakazuje określenie interfejsu w interfejsie.
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
Deskryptor tego interfejsu to android.bar.IWorld
. Jeśli brak adnotacji Descriptor
, opis będzie wyglądał tak: android.foo.IHello
.
Jest to przydatne, gdy chcesz zmienić nazwę już opublikowanego interfejsu. Ustawienie identycznego deskryptora przemianowanego interfejsu co deskryptora interfejsu przed przemianą umożliwia wzajemną komunikację obu interfejsów.
@hide w komentarzach
Kompilator AIDL rozpoznaje w komentarzach wartość @hide
i przekazuje ją do danych wyjściowych Javy, aby umożliwić ich odbiór. Dzięki temu komentarzowi system kompilacji Androida wie, że interfejsy AIDL API nie są interfejsami SDK API.
@deprecated w komentarzach
Kompilator AIDL rozpoznaje @deprecated
w komentarzach jako tag identyfikujący element AIDL, którego nie należy już używać.
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
Każdy backend oznacza wycofane elementy za pomocą adnotacji lub atrybutu specyficznego dla backendu, aby w przypadku odwołania do wycofanych elementów kod klienta otrzymał ostrzeżenie. Na przykład do wygenerowanego kodu Java dołączone są adnotacja @Deprecated
i tag @deprecated
.