Adnotacje w AIDL

AIDL obsługuje adnotacje, które dają kompilatorowi AIDL dodatkowe informacje o elemencie z adnotacjami, co ma również wpływ na wygenerowany kod pośredniczący.

Składnia jest podobna do składni Javy:

@AnnotationName(argument1=value, argument2=value) AidlEntity

W tym przypadku AnnotationName jest nazwą adnotacji, a AidlEntity jest jednostką AIDL, taką jak interface Foo , void method() lub int arg . Adnotacja jest dołączona do jednostki, która po niej następuje.

Niektóre adnotacje mogą mieć argumenty umieszczone w nawiasach, jak pokazano powyżej. Adnotacje bez argumentu nie wymagają nawiasów. Na przykład:

@AnnotationName AidlEntity

Te adnotacje nie są takie same jak adnotacje Java, chociaż wyglądają bardzo podobnie. Użytkownicy nie mogą definiować niestandardowych adnotacji AIDL; wszystkie adnotacje są wstępnie zdefiniowane. Niektóre adnotacje wpływają tylko na określony backend i nie działają w innych backendach. Mają różne ograniczenia, do których można je przywiązać.

Poniżej znajduje się lista predefiniowanych adnotacji AIDL:

Adnotacje Dodano w wersji na Androida
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

nullable

nullable deklaruje, że nie można podać wartości jednostki z adnotacjami.

Ta adnotacja może być dołączona tylko do typów zwracanych metod, parametrów metod i pól paczkowanych.

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 pierwotnych. Oto błąd.

void method(in @nullable int a); // int is a primitive type

Ta adnotacja jest niedostępna dla backendu Java. Dzieje się tak, ponieważ w Javie wszystkie typy nieprymitywne są przekazywane przez referencję, co może mieć null .

W zapleczu CPP @nullable T mapuje na std::unique_ptr<T> w systemie Android 11 lub nowszym oraz std::optional<T> w systemie Android 12 lub nowszym.

W zapleczu NDK @nullable T zawsze mapuje na std::optional<T> .

W przypadku typu listowego L , takiego jak T[] lub List<T> , @nullable L mapuje do std::optional<std::vector<std::optional<T>>> (lub std::unique_ptr<std::vector<std::unique_ptr<T>>> w przypadku backendu CPP dla systemu Android 11 lub starszego).

Istnieje wyjątek od tego mapowania. Gdy T jest interfejsem IBinder lub AIDL, @nullable oznacza brak operacji. Innymi słowy, zarówno @nullable IBinder , jak i IBinder równym stopniu mapują na android::sp<IBinder> , który już dopuszcza wartość null, ponieważ jest silnym wskaźnikiem (odczyty CPP nadal wymuszają wartość null, ale typ nadal to android::sp<IBinder> ).

Począwszy od Androida 13, @nullable(heap=true) może być używany dla pól parcelowalnych do modelowania typów rekurencyjnych. @nullable(heap=true) nie można używać z parametrami metody ani typami zwracanymi. Po opatrzeniu adnotacją pole jest mapowane na przydzieloną stertę referencję std::unique_ptr<T> w backendach CPP/NDK. @nullable(heap=true) nie działa w backendzie Java.

utf8InCpp

utf8InCpp deklaruje, że String jest reprezentowany w formacie UTF8 dla backendu CPP. Jak sama nazwa wskazuje, adnotacja jest niedostępna dla innych backendów. W szczególności, String jest zawsze UTF16 w zapleczu Java i UTF8 w zapleczu NDK.

Ta adnotacja może być dołączona wszędzie tam, gdzie może być użyty typ String , w tym wartości zwracane, parametry, deklaracje stałych i pola parcelable.

W przypadku zaplecza CPP, @utf8InCpp String w AIDL mapuje na std::string , podczas gdy String bez adnotacji mapuje na android::String16 , gdzie używany jest UTF16.

Zauważ, że istnienie adnotacji utf8InCpp nie zmienia sposobu, w jaki ciągi są przesyłane przez przewód. Ciągi są zawsze przesyłane w sieci jako UTF16. Ciąg z adnotacjami utf8InCpp jest konwertowany na UTF16 przed przesłaniem. Po odebraniu ciągu jest on konwertowany z UTF16 na UTF8, jeśli został oznaczony jako utf8InCpp .

VintfStabilność

VintfStability deklaruje, że typ zdefiniowany przez użytkownika (interfejs, parcelable i enum) może być używany w całym systemie i domenach dostawców. Zobacz AIDL dla warstw HAL, aby uzyskać więcej informacji na temat współdziałania systemu z dostawcą.

Adnotacja nie zmienia sygnatury typu, ale gdy jest ustawiona, wystąpienie typu jest oznaczane jako stabilne, dzięki czemu może podróżować między procesami dostawcy i systemu.

Adnotację można dołączyć tylko do deklaracji typu zdefiniowanego przez użytkownika, jak pokazano poniżej:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Gdy typ jest opatrzony adnotacją VintfStability , każdy inny typ, do którego odwołuje się typ, również powinien być oznaczony jako taki. W poniższym przykładzie Data i IBar powinny być opatrzone adnotacjami 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 {...}

Ponadto pliki AIDL definiujące typy z adnotacjami VintfStability mogą być budowane tylko przy użyciu typu modułu aidl_interface Soong, z właściwością stability ustawioną na "vintf" .

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

Nieobsługiwane użycie aplikacji

Adnotacja UnsupportedAppUsage wskazuje, że typ AIDL z adnotacjami jest częścią interfejsu innego niż SDK, który był dostępny dla starszych aplikacji. Zobacz Ograniczenia dotyczące interfejsów innych niż SDK, aby uzyskać więcej informacji o ukrytych interfejsach API.

Adnotacja UnsupportedAppUsage nie wpływa na zachowanie wygenerowanego kodu. Adnotacja opisuje tylko wygenerowaną klasę Java z adnotacją Java o tej samej nazwie.

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

To jest zakaz dla backendów innych niż Java.

Poparcie

Adnotacja Backing określa typ magazynu typu wyliczenia AIDL.

@Backing(type="int")
enum Color { RED, BLUE, }

W backendzie CPP powyższe emituje klasę enum C++ typu int32_t .

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

Jeśli adnotacja zostanie pominięta, zakłada się, że type jest byte , który jest mapowany na int8_t dla backendu CPP.

Argument type można ustawić tylko na następujące typy całkowite:

  • byte (8 bitów szerokości)
  • int (szerokość 32-bitowa)
  • long (szerokość 64-bitowa)

JavaTylko stabilna Parcelable

JavaOnlyStableParcelable oznacza deklarację parcelable (nie definicję) jako stabilną, dzięki czemu można 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 parcelables bycie stabilnym wymaga, aby jego 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 element parcelable był nieustrukturyzowany (lub właśnie zadeklarowany), nie można się do niego odnieść.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable umożliwia pominięcie kontroli, gdy element parcelable, do którego się odwołujesz, jest już bezpiecznie dostępny jako część Android SDK.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaPochodna

JavaDerive automatycznie generuje metody dla typów paczkowalnych w backendzie Java.

@JavaDerive(equals = true, toString = true)
parcelable Data {
  int number;
  String str;
}

Adnotacja wymaga dodatkowych parametrów, aby kontrolować, co ma zostać wygenerowane. Obsługiwane parametry to:

  • equals=true generuje metody equals i hashCode .
  • toString=true generuje metodę toString , która wypisuje nazwę typu i pola. Na przykład: Data{number: 42, str: foo}

JavaDefault

JavaDefault , dodana w systemie Android 13, kontroluje, czy generowana jest domyślna obsługa wersji implementacji (dla setDefaultImpl ). To wsparcie nie jest już generowane domyślnie w celu zaoszczędzenia miejsca.

Przekazywanie Java

JavaPassthrough umożliwia opisywanie wygenerowanego interfejsu Java API za pomocą dowolnej adnotacji Java.

Następujące adnotacje w 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 Java, nie zostanie on wychwycony przez kompilator AIDL, ale przez kompilator Java.

Ta adnotacja może być dołączona do dowolnej jednostki AIDL. Ta adnotacja jest niedozwolona dla backendów innych niż Java.

Naprawiono rozmiar

FixedSize oznacza ustrukturyzowany działek jako stały rozmiar. Po oznaczeniu działki nie będzie można dodać do niej nowych pól. Wszystkie pola parcelable muszą być również typami o stałym rozmiarze, w tym typami pierwotnymi, wyliczeniami, tablicami o stałym rozmiarze i innymi parcelable oznaczonymi przez FixedSize .

Nie zapewnia to żadnej gwarancji dla różnych bitów i nie należy na nim polegać w przypadku komunikacji o mieszanym bitwie.

Deskryptor

Descriptor wymusza określenie deskryptora interfejsu.

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

Deskryptorem powyższego interfejsu jest android.bar.IWorld . Jeśli brakuje adnotacji Descriptor , deskryptorem będzie android.foo.IHello .

Jest to przydatne do zmiany nazwy już opublikowanego interfejsu. Uczynienie deskryptora interfejsu o zmienionej nazwie takim samym jak deskryptor interfejsu przed zmianą nazwy umożliwi dwóm interfejsom komunikowanie się ze sobą.

@ukryj w komentarzach

Kompilator AIDL rozpoznaje @hide w komentarzach i przekazuje go do wyjścia Java, aby metalava mogła go pobrać. Ten komentarz zapewnia, że ​​system kompilacji systemu Android wie, że interfejsy API AIDL nie są interfejsami API zestawu SDK.

@przestarzałe w komentarzach

Kompilator AIDL rozpoznaje @deprecated w komentarzach jako znacznik 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 przestarzałe jednostki adnotacją/atrybutem specyficznym dla backendu, aby kod klienta był ostrzegany, jeśli odwołuje się do przestarzałych jednostek. Na przykład adnotacja @Deprecated i tag @deprecated są dołączone do kodu wygenerowanego w języku Java.