Annotazioni in AIDL

AIDL supporta le annotazioni che forniscono al compilatore AIDL informazioni aggiuntive sull'elemento annotato, che influiscono anche sul codice stub generato.

La sintassi è simile a quella di Java:

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

Qui, AnnotationName è il nome dell'annotazione e AidlEntity è un'entità AIDL come interface Foo, void method() o int arg. Un'annotazione è collegata all'entità che la segue.

Alcune annotazioni possono avere argomenti impostati all'interno delle parentesi, come mostrato nell'esempio precedente. Le annotazioni che non hanno un argomento non richiedono le parentesi. Ad esempio:

@AnnotationName AidlEntity

Queste annotazioni non sono le stesse delle annotazioni Java, anche se sembrano simili. Tutte le annotazioni sono predefinite e hanno limitazioni per la posizione in cui puoi collegarle. Alcune annotazioni influiscono solo su un determinato backend e sono no-op in altri backend.

Di seguito è riportato l'elenco delle annotazioni AIDL predefinite:

AnnotazioniAggiunte nella versione di Android
nullable7
utf8InCpp7
VintfStability11
UnsupportedAppUsage10
Hide11
Backing11
NdkOnlyStableParcelable14
JavaOnlyStableParcelable11
JavaDerive12
JavaPassthrough12
FixedSize12
Descriptor12

nullable

nullable dichiara che il valore dell'entità annotata può essere null.

Puoi collegare questa annotazione solo ai tipi di restituzione dei metodi, ai parametri dei metodi e ai campi parcelable:

interface IFoo {
    // method return types
    @nullable Data method();

    // method parameters
    void method2(in @nullable Data d);
}

parcelable Data {
    // parcelable fields
    @nullable Data d;
}

Le annotazioni non possono essere collegate ai tipi primitivi. Di seguito è riportato un errore:

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

Questa annotazione è no-op per il backend Java. In Java, tutti i tipi non primitivi vengono passati per riferimento, che potrebbe essere null.

Nel backend CPP, @nullable T esegue il mapping a std::unique_ptr<T> in Android 11 o versioni precedenti e a std::optional<T> in Android 12 o versioni successive.

Nel backend NDK, @nullable T esegue il mapping a std::optional<T>.

Nel backend Rust, @nullable T esegue il mapping a Option<T>.

Per un tipo simile a un elenco L ad esempio T[] o List<T>, @nullable L esegue il mapping a std::optional<std::vector<std::optional<T>>> (o std::unique_ptr<std::vector<std::unique_ptr<T>>> nel caso del backend CPP per Android 11 o versioni precedenti).

Esiste un'eccezione a questo mapping. Quando T è IBinder o un'interfaccia AIDL, @nullable è no-op per tutti i backend tranne Rust. In altre parole, sia @nullable IBinder sia IBinder eseguono il mapping a android::sp<IBinder>, che è già nullable perché è un puntatore forte (le letture CPP applicano comunque la nullabilità, ma il tipo è comunque android::sp<IBinder>). In Rust, questi tipi sono nullable solo se annotati con @nullable. Se annotati, eseguono il mapping a Option<T>.

A partire da Android 13, @nullable(heap=true) può essere utilizzato per i campi parcelable per modellare i tipi ricorsivi. @nullable(heap=true) non può essere utilizzato con i parametri dei metodi o i tipi di restituzione. Se annotato, il campo viene mappato a un riferimento allocato nell'heap std::unique_ptr<T> nei backend CPP e NDK. @nullable(heap=true) è no-op nel backend Java.

utf8InCpp

utf8InCpp dichiara che String è rappresentato in formato UTF8 per il backend CPP. Come indica il nome, l'annotazione è no-op per altri backend. In particolare, String è sempre UTF16 nel backend Java e UTF8 nel backend NDK.

Questa annotazione può essere collegata ovunque sia possibile utilizzare il tipo String, inclusi valori di restituzione, parametri, dichiarazioni costanti e campi parcelable.

Per il backend CPP, @utf8InCpp String in AIDL esegue il mapping a std::string, dove String senza l'annotazione esegue il mapping a android::String16 dove viene utilizzato UTF16.

VintfStability

VintfStability dichiara che un tipo definito dall'utente (interfaccia, parcelable ed enum) può essere utilizzato nei domini di sistema e fornitore. Per saperne di più sull' interoperabilità tra sistema e fornitore, consulta AIDL per HAL.

L'annotazione non modifica la firma del tipo, ma quando è impostata, l'istanza del tipo viene contrassegnata come stabile in modo che possa spostarsi tra i processi del fornitore e del sistema.

L'annotazione può essere collegata solo alle dichiarazioni di tipo definite dall'utente, come mostrato di seguito:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Quando un tipo è annotato con VintfStability, anche qualsiasi altro tipo a cui viene fatto riferimento nel tipo deve essere annotato come tale. Nell'esempio seguente, sia Data sia IBar devono essere annotati con 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 {...}

Inoltre, i file AIDL che definiscono i tipi annotati con VintfStability possono essere compilati solo utilizzando il tipo di modulo Soong aidl_interface, con la proprietà stability impostata su vintf:

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

UnsupportedAppUsage

L'annotazione UnsupportedAppUsage indica che il tipo AIDL annotato fa parte dell'interfaccia non SDK a cui le app legacy hanno avuto accesso. Per saperne di più sulle API nascoste, consulta Limitazioni relative alle interfacce non SDK.

L'annotazione UnsupportedAppUsage non influisce sul comportamento del codice generato. L'annotazione annota solo la classe Java generata con l'annotazione Java con lo stesso nome:

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

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

Questa annotazione è no-op per i backend non Java.

Annotazione Backing

L'annotazione Backing specifica il tipo di archiviazione di un tipo enum AIDL:

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

Nel backend CPP, viene generata una classe enum C++ di tipo int32_t:

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

Se l'annotazione viene omessa, si presuppone che type sia byte, che esegue il mapping a int8_t per il backend CPP.

L'argomento type può essere impostato solo sui seguenti tipi integrali:

  • byte (8 bit)
  • int (32 bit)
  • long (64 bit)

NdkOnlyStableParcelable

NdkOnlyStableParcelable contrassegna una dichiarazione parcelable (non una definizione) come stabile in modo che possa essere referenziata da altri tipi AIDL stabili. È simile a JavaOnlyStableParcelable, ma NdkOnlyStableParcelable contrassegna una dichiarazione parcelable come stabile per il backend NDK anziché per Java.

Per utilizzare questo parcelable:

  • Devi specificare ndk_header.
  • Devi avere una libreria NDK che specifichi il parcelable e la libreria deve essere compilata nella libreria. Ad esempio, nel sistema di compilazione principale su un modulo cc_*, utilizza static_libs o shared_libs. Per aidl_interface, aggiungi la libreria in additional_shared_libraries in Android.bp.

JavaOnlyStableParcelable

JavaOnlyStableParcelable contrassegna una dichiarazione parcelable (non una definizione) come stabile in modo che possa essere referenziata da altri tipi AIDL stabili.

AIDL stabile richiede che tutti i tipi definiti dall'utente siano stabili. Per i parcelable, la stabilità richiede che i relativi campi siano descritti in modo esplicito nel file di origine 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
}

Se il parcelable non è strutturato (o è solo dichiarato), non è possibile farvi riferimento:

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable consente di ignorare il controllo quando il parcelable a cui fai riferimento è disponibile in modo sicuro come parte dell'SDK Android:

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive genera automaticamente i metodi per i tipi parcelable nel backend Java:

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

L'annotazione richiede parametri aggiuntivi per controllare cosa generare. I parametri supportati sono:

  • equals=true genera i metodi equals e hashCode.
  • toString=true genera il metodo toString che stampa il nome del tipo e dei campi, ad esempio Data{number: 42, str: foo}.

JavaDefault (obsoleta)

JavaDefault, aggiunta in Android 13, controlla se viene generato il supporto per il controllo delle versioni dell'implementazione predefinita (per setDefaultImpl). Questo supporto non viene più generato per impostazione predefinita per risparmiare spazio.

JavaPassthrough

JavaPassthrough consente di annotare l'API Java generata con un'annotazione Java arbitraria.

Queste annotazioni in AIDL:

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

diventano le seguenti nel codice Java generato:

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

Il valore del parametro annotation viene emesso direttamente. Il compilatore AIDL non esamina il valore del parametro. Se si verifica un errore di sintassi a livello Java, non verrà rilevato dal compilatore AIDL, ma dal compilatore Java.

Questa annotazione può essere collegata a qualsiasi entità AIDL. Questa annotazione è no-op per i backend non Java.

RustDerive

RustDerive implementa automaticamente i tratti per i tipi Rust generati.

L'annotazione richiede parametri aggiuntivi per controllare cosa generare. I parametri supportati sono:

  • Copy=true
  • Clone=true
  • Ord=true
  • PartialOrd=true
  • Eq=true
  • PartialEq=true
  • Hash=true

Per le spiegazioni di questi tratti, consulta la documentazione di Rust.

FixedSize

FixedSize contrassegna un parcelable strutturato come di dimensioni fisse. Una volta contrassegnato, non puoi aggiungere nuovi campi al parcelable. Tutti i campi del parcelable devono essere tipi di dimensioni fisse, inclusi tipi primitivi, enum, array di dimensioni fisse e altri parcelable contrassegnati con FixedSize.

Gli oggetti FixedSize hanno dimensioni e allineamenti stabili nel backend ndk.

Tipo Dimensioni (byte) Allineamento (byte)
boolean 1 1
byte 1 1
char 2 2
int 4 4
long 8 8
float 4 4
double 8 8
parcelable Dimensione totale di tutti i campi Allineamento più grande di tutti i campi
union Dimensione più grande di tutti i campi Allineamento più grande di tutti i campi
enum Dimensione del tipo di supporto Allineamento del tipo di supporto
T[N] (array di dimensioni fisse) Dimensione di T * N Allineamento di T
String, IBinder, FileDescriptor, ParcelFileDescriptor N/A N/A

Descriptor

Descriptor specifica forzatamente il descrittore dell'interfaccia di un'interfaccia:

package android.foo;

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

Il descrittore di questa interfaccia è android.bar.IWorld. Se l'annotazione Descriptor non è presente, il descrittore sarebbe android.foo.IHello.

Questa annotazione è utile per rinominare un'interfaccia già pubblicata. Se il descrittore dell'interfaccia rinominata è lo stesso dell'interfaccia prima della ridenominazione, le due interfacce possono comunicare tra loro.

@hide nei commenti

Il compilatore AIDL riconosce @hide nei commenti e lo passa all'output Java per il recupero di metalava. Questo commento contribuisce a garantire che il sistema di compilazione Android riconosca che le API AIDL non sono API SDK.

@deprecated nei commenti

Il compilatore AIDL riconosce @deprecated nei commenti come tag per identificare un'entità AIDL che non deve più essere utilizzata:

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

Ogni backend contrassegna le entità obsolete con un'annotazione o un attributo specifico del backend in modo che il codice client venga avvisato se fa riferimento alle entità obsolete. Ad esempio, l'annotazione @Deprecated e il tag @deprecated vengono collegati al codice Java generato.