Adnotacje w AIDL

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 elementu, który na niej występuje, dołączona jest adnotacja.

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

@AnnotationName AidlEntity

Adnotacje te różnią się od adnotacji w Javie, chociaż wyglądają bardzo podobnie. Użytkownicy nie mogą definiować niestandardowych adnotacji AIDL. Wszystkie adnotacje są wstępnie zdefiniowane. Niektóre adnotacje mają wpływ tylko na określony backend, a w innych nie działają. Obowiązują różne ograniczenia, do których można je dołączyć.

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 nie można podać wartości elementu z adnotacjami.

Tę adnotację można dołączyć tylko do zwracanych typów metod, parametrów metod i pól parcelables.

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

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

Ta adnotacja nie działa w backendzie Java. Jest to spowodowane tym, że w Javie wszystkie typy inne niż podstawowe są przekazywane przez odwołanie, którym może być parametr 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 przypadku typu listy L, np. T[] lub List<T>, wartość @nullable L jest mapowana na wartość 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 starszym).

Występuje wyjątek od tego mapowania. Gdy T to IBinder lub interfejs AIDL, @nullable jest bezobsługowy. Inaczej mówiąc, zarówno @nullable IBinder, jak i IBinder są mapowane w równym stopniu na android::sp<IBinder>, który już ma wartość null, ponieważ jest silny wskaźnik (CPP nadal wymusza dopuszczenie wartości null, ale typ to android::sp<IBinder>).

Począwszy od Androida w wersji 13 usługi @nullable(heap=true) można używać w przypadku pól parcels do modelowania typów rekurencyjnych. Parametru @nullable(heap=true) nie można używać z parametrami metody ani zwracanymi typami. Gdy to pole jest oznaczone adnotacją, w backendach CPP/NDK pole jest mapowane na odwołanie std::unique_ptr<T> przydzielone do stosu. Interfejs @nullable(heap=true) nie działa w backendzie Java.

UTf8InCpp

utf8InCpp deklaruje, że dla backendu CPP identyfikator String jest reprezentowany w formacie UTF8. Jak sama nazwa wskazuje, adnotacja nie jest operacją w innych backendach. Konkretnie String to zawsze kodowanie UTF16 w backendzie Java i UTF8 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 backendzie CPP @utf8InCpp String w AIDL jest mapowany na std::string, podczas gdy String bez adnotacji jest mapowany na android::String16, gdzie jest używany kod UTF16.

Pamiętaj, że istnienie adnotacji utf8InCpp nie zmienia sposobu przesyłania ciągów znaków przez przewód. Ciągi znaków są zawsze przesyłane w formacie UTF16 przez przewód. Ciąg znaków z adnotacjami utf8InCpp jest konwertowany na UTF16 przed jego przesłaniem. Po odebraniu ciągu znaków zostaje on zmieniony z UTF16 na UTF8, jeśli został oznaczony jako utf8InCpp.

Stabilność Vintf

VintfStability deklaruje, że typ zdefiniowany przez użytkownika (interfejs, parcelable i enum) może być używany w domenach systemu i dostawców. Więcej informacji o interoperacyjności systemów dostawców znajdziesz w artykule AIDL dla HAL.

Adnotacja nie zmienia podpisu typu, ale gdy jest ustawiony, instancja typu jest oznaczana jako stabilna, dzięki czemu może przemieszczać się 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, powinien być również opatrzony adnotacją do każdego innego typu, do którego odwołuje się typ. W poniższym przykładzie do właściwości Data i IBar należy dodać 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 {...}

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",
}

Nieobsługiwane użycie aplikacji

Adnotacja UnsupportedAppUsage oznacza, że typ AIDL z adnotacjami jest częścią interfejsu innego niż SDK, który był dostępny dla starszych aplikacji. Więcej informacji o ukrytych interfejsach API znajdziesz w artykule Ograniczenia interfejsów innych niż SDK.

Adnotacja UnsupportedAppUsage nie ma wpływu na działanie 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 ustawienie nie jest obsługiwane dla backendów innych niż Java.

Kopia zapasowa

Adnotacja Backing określa typ pamięci wyliczenia 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 to byte, który jest mapowany na int8_t w przypadku backendu CPP.

Argument type można ustawić tylko na te typy całek:

  • byte (8-bitowy)
  • int (32-bitowy)
  • long (64-bitowy)

NdkOnlyStableParcelable,

NdkOnlyStableParcelable oznacza deklarację możliwości parlamentarną (nie definicję) jako stabilną, aby można ją było odwoływać z innych stabilnych typów AIDL. Wygląda to podobnie do JavaOnlyStableParcelable, ale NdkOnlyStableParcelable oznacza deklarację możliwej do spakowania jako stabilną dla backendu NDK, a nie dla Javy.

Aby użyć tej działki:

  • Musisz określić ndk_header.
  • Musisz mieć bibliotekę NDK określającą możliwość przesyłki i skompilować ją w bibliotekę. Na przykład w podstawowym systemie kompilacji modułu cc_* użyj static_libs lub shared_libs. W przypadku aidl_interface dodaj bibliotekę w katalogu additional_shared_libraries w pliku Android.bp.

JavaOnlyStableParcelable,

JavaOnlyStableParcelable oznacza deklarację możliwości parlamentarną (nie definicję) jako stabilną, aby można ją było odwoływać z innych stabilnych typów AIDL.

Stabilna 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 parcelable był nieuporządkowany (lub właśnie zadeklarowany), nie można się do niego odwołać.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable umożliwia zastąpienie sprawdzenia, gdy parcel, do którego się odwołujesz, jest już bezpiecznie dostępny 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:

  • Funkcja equals=true generuje metody equals i hashCode.
  • toString=true generuje metodę toString, która wyświetla nazwę typu i pola. Przykład: Data{number: 42, str: foo}

Ustawienie domyślne Java

JavaDefault, dodana w Androidzie 13, określa, czy ma być generowana domyślna obsługa wersji implementacji (w przypadku aplikacji setDefaultImpl). Ta obsługa nie jest już domyślnie generowana, aby zaoszczędzić miejsce.

Przekazywanie języka Java

JavaPassthrough umożliwia dodawanie do wygenerowanego interfejsu Java API adnotacji przy użyciu dowolnej adnotacji w języku 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 błąd składni na poziomie języka Java, nie zostanie on przechwycony przez kompilator AIDL, a jedynie.

Tę adnotację można dołączyć do dowolnej encji AIDL. Nie można jej używać dla backendów innych niż Java.

Stały rozmiar

FixedSize oznacza działkę strukturalną jako stały rozmiar. Po oznaczeniu tego obiektu nie będzie można dodawać do niego nowych pól. Wszystkie pola paczki muszą też mieć typy o stałym rozmiarze, w tym typy podstawowe, wyliczenia, tablice o stałym rozmiarze i inne obiekty oznaczone za pomocą atrybutu FixedSize.

Nie daje to żadnej gwarancji dotyczącej różnych bitów i nie należy polegać na komunikacji o mieszanych bitach.

Opis

Pole Descriptor wymuszone określa deskryptor interfejsu interfejsu.

package android.foo;

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

Deskryptor tego interfejsu to android.bar.IWorld. Jeśli brakuje adnotacji Descriptor, deskryptorem jest android.foo.IHello.

Przydaje się to do zmiany nazwy opublikowanego już interfejsu. Dzięki temu, że deskryptor interfejsu ze zmienioną nazwą przed zmianą nazwy jest taki sam jak deskryptor interfejsu, oba interfejsy mogą się ze sobą komunikować.

@ukryj w komentarzach

Kompilator AIDL rozpoznaje w komentarzach ciąg @hide i przekazuje go do danych wyjściowych Java, aby umożliwić użycie metalava do odbioru. Dzięki temu systemowi kompilacji na Androida system kompilacji na Androida wie, że interfejsy API AIDL nie są interfejsami SDK.

@deprecated w komentarzach

Kompilator AIDL rozpoznaje w komentarzach encję @deprecated jako tag identyfikujący encję AIDL, której nie należy już używać.

interface IFoo {
  /** @deprecated use bar() instead */
  void foo();
  void bar();
}

Każdy backend oznacza wycofane elementy adnotacją lub atrybutem backendu, dzięki czemu kod klienta otrzyma ostrzeżenie, jeśli będzie się to wiązać z wycofanymi elementami. Na przykład adnotacja @Deprecated i tag @deprecated są dołączone do kodu wygenerowanego w języku Java.