AIDL obsługuje adnotacje, które dostarczają kompilatorowi AIDL dodatkowych informacji o elementach z adnotacjami. Ma to też wpływ na wygenerowany kod szkieletowy.
Składnia jest podobna do składni Javy:
@AnnotationName(argument1=value, argument2=value) AidlEntity
W tym przypadku AnnotationName to nazwa adnotacji, a AidlEntity to jednostka AIDL, np. interface Foo, void method() lub int arg. Do encji jest dołączona adnotacja, która za nią podąża.
Niektóre adnotacje mogą mieć argumenty ustawione w nawiasach, jak pokazano w poprzednim przykładzie. Adnotacje, które nie mają argumentu, nie wymagają nawiasów. Przykład:
@AnnotationName AidlEntity
Te adnotacje nie są takie same jak adnotacje Java, chociaż wyglądają podobnie. Wszystkie adnotacje są predefiniowane i mają ograniczenia dotyczące miejsc, w których można je dołączyć. Niektóre adnotacje mają wpływ tylko na określony backend, a w innych backendach nie mają żadnego działania.
Oto lista wstępnie zdefiniowanych adnotacji AIDL:
| Adnotacje | Dodano w wersji 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 |
dopuszczalna wartość null
nullable deklaruje, że wartość adnotowanej encji może być wartością null.
Tę adnotację możesz dołączyć tylko do typów zwracanych przez metody, parametrów metod i pól z możliwością przekazywania:
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 prostych. Wystąpił ten błąd:
void method(in @nullable int a); // int is a primitive type
W przypadku zaplecza Java ta adnotacja nie ma żadnego efektu. W języku Java wszystkie typy niepierwotne są przekazywane przez odwołanie, co może być null.
W backendzie CPP znak @nullable T jest mapowany na std::unique_ptr<T> na Androidzie 11 lub starszym oraz na std::optional<T> na Androidzie 12 lub nowszym.
W backendzie NDK wartość @nullable T jest mapowana na std::optional<T>.
W backendzie Rust @nullable T jest mapowane na Option<T>.
W przypadku typu listy L, takiego jak T[] lub List<T>, @nullable L jest mapowany na std::optional<std::vector<std::optional<T>>> (lub std::unique_ptr<std::vector<std::unique_ptr<T>>> w przypadku backendu CPP na Androidzie 11 lub starszym).
Od tego mapowania jest wyjątek. Gdy T jest IBinder lub interfejsem AIDL, @nullable nie ma wpływu na wszystkie backendy z wyjątkiem Rusta. Innymi słowy, zarówno @nullable IBinder, jak i IBinder są mapowane na android::sp<IBinder>, które jest już dopuszczalne wartości null, ponieważ jest silnym wskaźnikiem (odczyty w C++ nadal wymuszają dopuszczalność wartości null, ale typ to nadal android::sp<IBinder>). W Rust te typy to nullable tylko wtedy, gdy są oznaczone adnotacją @nullable. Jeśli są oznaczone, są mapowane na Option<T>.
Od Androida 13 można używać adnotacji @nullable(heap=true) w przypadku pól z możliwością przekazywania w pakietach do modelowania typów rekurencyjnych. @nullable(heap=true) nie można używać z parametrami metod ani typami zwracanych wartości. Jeśli pole jest oznaczone tym adnotacją, jest mapowane na referencję przydzieloną do sterty std::unique_ptr<T> w backendach CPP i NDK. @nullable(heap=true) nie ma wpływu na backendzie Java.
utf8InCpp
utf8InCpp deklaruje, że String jest reprezentowany w formacie UTF8 na potrzeby backendu CPP. Jak sama nazwa wskazuje, ta adnotacja nie ma wpływu na inne systemy backendowe.
W szczególności String jest zawsze zakodowany w UTF16 w przypadku backendu Java i w UTF8 w przypadku backendu NDK.
Tę adnotację można dołączyć w dowolnym miejscu, w którym można użyć typu String, w tym w przypadku wartości zwracanych, parametrów, deklaracji stałych i pól z możliwością przekazywania.
W przypadku backendu CPP @utf8InCpp String w AIDL jest mapowane na std::string, gdzie
String bez adnotacji jest mapowane na android::String16, w którym używane jest kodowanie UTF16.
VintfStability
VintfStability deklaruje, że zdefiniowany przez użytkownika typ (interfejs, obiekt do serializacji, i wyliczenie) może być używany w domenach systemowych i dostawcy. Więcej informacji o współdziałaniu systemu z dostawcą znajdziesz w artykule AIDL dla HAL-i.
Adnotacja nie zmienia sygnatury typu, ale po jej ustawieniu instancja typu jest oznaczana jako stabilna, dzięki czemu może być przekazywana między procesami dostawcy i systemu.
Adnotację można dołączyć tylko do deklaracji typów zdefiniowanych przez użytkownika, jak pokazano tutaj:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
Jeśli typ jest oznaczony adnotacją VintfStability, każdy inny typ, do którego odwołuje się ten typ, również powinien być oznaczony w ten sposób. W poniższym przykładzie zarówno Data, jak i IBar powinny być oznaczone adnotacją 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 {...}
Dodatkowo pliki AIDL definiujące typy oznaczone adnotacją VintfStability
można tworzyć tylko za pomocą modułu Soong typu aidl_interface z właściwością stability ustawioną na vintf:
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
Adnotacja UnsupportedAppUsage oznacza, że typ AIDL z adnotacją jest częścią interfejsu innego niż SDK, który był dostępny dla starszych aplikacji.
Więcej informacji o ukrytych interfejsach API znajdziesz w sekcji Ograniczenia dotyczące interfejsów innych niż SDK.
Adnotacja UnsupportedAppUsage nie wpływa na działanie wygenerowanego kodu. Adnotacja dodaje adnotację tylko do wygenerowanej klasy Java z adnotacją Java o tej samej nazwie:
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
W przypadku backendów innych niż Java ta operacja nie ma żadnego efektu.
Adnotacja dotycząca podkładu
Adnotacja Backing określa typ pamięci masowej typu wyliczeniowego AIDL:
@Backing(type="int")
enum Color { RED, BLUE, }
W backendzie CPP generuje to klasę wyliczeniową C++ typu int32_t:
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
Jeśli adnotacja zostanie pominięta, przyjmuje się, że type ma wartość byte, która w przypadku backendu CPP jest mapowana na int8_t.
Argument type może mieć tylko te typy całkowite:
byte(8-bitowa)int(32-bitowa)long(64-bitowa)
NdkOnlyStableParcelable
NdkOnlyStableParcelable oznacza deklarację (nie definicję) typu parcelable jako stabilną, aby można było się do niej odwoływać z innych stabilnych typów AIDL. Działa to podobnie jak JavaOnlyStableParcelable, ale NdkOnlyStableParcelable oznacza deklarację z możliwością przekazywania jako stabilną w przypadku backendu NDK, a nie Javy.
Aby użyć tego obiektu Parcelable:
- Musisz podać wartość
ndk_header. - Musisz mieć bibliotekę NDK określającą obiekt Parcelable, a biblioteka musi być skompilowana w bibliotece. Na przykład w podstawowym systemie kompilacji w module
cc_*użyjstatic_libslubshared_libs. W przypadkuaidl_interfacedodaj bibliotekę w sekcjiadditional_shared_librarieswAndroid.bp.
JavaOnlyStableParcelable
JavaOnlyStableParcelable oznacza deklarację (nie definicję) typu parcelable jako stabilną, aby można było się do niej odwoływać z innych stabilnych typów AIDL.
Stabilny AIDL wymaga, aby wszystkie typy zdefiniowane przez użytkownika były stabilne. W przypadku obiektów Parcelable stabilność wymaga, aby ich pola były wyraźnie opisane 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 jest nieustrukturyzowany (lub tylko zadeklarowany), nie można się do niego odwoływać:
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable umożliwia zastąpienie sprawdzania, gdy odwoływany obiekt Parcelable jest bezpiecznie dostępny w ramach pakietu Android SDK:
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive automatycznie generuje metody dla typów możliwych do przekazania w backendzie Javy:
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
Adnotacja wymaga dodatkowych parametrów, aby określić, co ma być generowane. Obsługiwane parametry to:
equals=truegeneruje metodyequalsihashCode.toString=truegeneruje metodętoString, która wyświetla nazwę typu i pola, np.Data{number: 42, str: foo}.
JavaDefault (wycofane)
JavaDefault, dodany w Androidzie 13, określa, czy ma być generowana domyślna obsługa wersji implementacji (w przypadku setDefaultImpl). Aby zaoszczędzić miejsce, ta obsługa nie jest już domyślnie generowana.
JavaPassthrough
JavaPassthrough umożliwia dodanie do wygenerowanego interfejsu Java API dowolnej adnotacji Java.
Te adnotacje w AIDL:
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")
w wygenerowanym kodzie Javy zmieni się w:
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
Wartość parametru annotation jest emitowana bezpośrednio. Kompilator AIDL nie sprawdza wartości parametru. Jeśli wystąpi błąd składni na poziomie języka Java, nie zostanie on wykryty przez kompilator AIDL, ale przez kompilator języka Java.
Tę adnotację można dołączyć do dowolnej jednostki AIDL. W przypadku backendów innych niż Java ta adnotacja nie ma żadnego działania.
RustDerive
RustDerive automatycznie implementuje cechy dla wygenerowanych typów Rusta.
Adnotacja wymaga dodatkowych parametrów, aby określić, co ma być generowane. Obsługiwane parametry to:
Copy=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
Wyjaśnienia tych cech znajdziesz w dokumentacji języka Rust.
FixedSize
FixedSize oznacza strukturalny obiekt Parcelable jako o stałym rozmiarze. Po oznaczeniu nie można dodawać nowych pól do obiektu Parcelable. Wszystkie pola obiektu z interfejsem Parcelable muszą być typami o stałym rozmiarze, w tym typami prostymi, wyliczeniowymi, tablicami o stałym rozmiarze i innymi obiektami z interfejsem Parcelable oznaczonymi symbolem FixedSize.
Obiekty FixedSize mają stałe rozmiary i wyrównanie w backendzie ndk.
| Typ | Rozmiar (w bajtach) | Wyrównanie (bajty) |
|---|---|---|
boolean |
1 |
1 |
byte |
1 |
1 |
char |
2 |
2 |
int |
4 |
4 |
long |
8 |
8 |
float |
4 |
4 |
double |
8 |
8 |
parcelable |
Łączny rozmiar wszystkich pól | Największe wyrównanie wszystkich pól |
union |
Największy rozmiar wszystkich pól | Największe wyrównanie wszystkich pól |
enum |
Rozmiar typu podkładu | Wyrównanie typu podkładu |
T[N] (tablica o stałym rozmiarze) |
Rozmiar: T * N |
Wyrównanie: T |
String, IBinder, FileDescriptor, ParcelFileDescriptor |
N/A |
N/A |
Deskryptor
Descriptor wymusza określenie deskryptora interfejsu:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
Deskryptor tego interfejsu to android.bar.IWorld. Jeśli brakuje adnotacji
Descriptor, opis będzie miał postać
android.foo.IHello.
Jest to przydatne w przypadku zmiany nazwy opublikowanego już interfejsu. Ustawienie deskryptora zmienionego interfejsu na taki sam jak deskryptor interfejsu przed zmianą nazwy umożliwia komunikację między tymi dwoma interfejsami.
@hide w komentarzach
Kompilator AIDL rozpoznaje @hide w komentarzach i przekazuje je do danych wyjściowych w języku Java, aby mogły być używane przez metalavę. Ten komentarz pomaga zapewnić, że system kompilacji Androida rozpoznaje, że interfejsy API AIDL nie są interfejsami API pakietu SDK.
@deprecated w komentarzach
Kompilator AIDL rozpoznaje @deprecated w komentarzach jako tag identyfikujący jednostkę AIDL, która nie powinna być już używana:
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
Każdy backend oznacza wycofane jednostki za pomocą adnotacji lub atrybutu specyficznego dla backendu, aby ostrzegać kod klienta, jeśli odwołuje się on do wycofanych jednostek. Na przykład adnotacja @Deprecated i tag @deprecated są dołączane do wygenerowanego kodu Java.