Annotazioni in AIDL

AIDL supporta annotazioni che forniscono al compilatore AIDL informazioni aggiuntive sull'elemento annotato, che influisce 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. All'entità che la segue viene allegata un'annotazione.

Alcune annotazioni possono avere argomenti impostati tra parentesi, come mostrato sopra. Le annotazioni che non hanno un argomento non hanno bisogno delle parentesi. Ecco alcuni esempi:

@AnnotationName AidlEntity

Queste annotazioni sono diverse da quelle Java, anche se sono molto simili. Gli utenti non possono definire annotazioni AIDL personalizzate perché sono tutte predefinite. Alcune annotazioni interessano solo un determinato backend e non sono operative in altri backend. Possono essere associati a diverse limitazioni.

Ecco l'elenco delle annotazioni AIDL predefinite:

Annotazioni Aggiunto nella versione di Android
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
NdkOnlyStableParcelable 14
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

annullabile

nullable dichiara che il valore dell'entità annotata potrebbe non essere fornito.

Questa annotazione può essere collegata solo ai tipi restituiti dal metodo, ai parametri del metodo e ai campi assegnabili.

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 associate ai tipi primitivi. Quello che segue è un errore.

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

Questa annotazione è autonoma per il backend Java. Questo perché in Java tutti i tipi non primitivi vengono passati per riferimento, che potrebbe essere null.

Nel backend CPP, @nullable T viene mappato 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 viene sempre mappato a std::optional<T>.

Per un tipo di tipo elenco L come T[] o List<T>, @nullable L viene mappato 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 questa mappatura. Quando T è IBinder o un'interfaccia AIDL, @nullable è una soluzione autonoma. In altre parole, sia @nullable IBinder che IBinder vengono mappati equamente a android::sp<IBinder>, che è già null perché è un pointer elevato (CPP legge comunque applicabilità di valori null, ma il tipo è ancora android::sp<IBinder>).

A partire da Android 13, @nullable(heap=true) può essere utilizzato per i campi assegnabili al modello di tipi ricorsivi. Non è possibile utilizzare @nullable(heap=true) con i parametri dei metodi o i tipi restituiti. Se annotato, il campo viene mappato a un riferimento std::unique_ptr<T> allocato nell'heap nei backend CPP/NDK. @nullable(heap=true) è autonomo nel backend Java.

Utf8InCpp

utf8InCpp dichiara che un String è rappresentato in formato UTF8 per il backend CPP. Come indica il suo nome, l'annotazione è autonoma per altri backend. Nello specifico, 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 restituiti, parametri, dichiarazioni costanti e campi assegnabili.

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

Tieni presente che l'esistenza dell'annotazione utf8InCpp non cambia il modo in cui le stringhe vengono trasmesse tramite cavo. Le stringhe vengono sempre trasmesse come UTF16 via cavo. Una stringa annotata utf8InCpp viene convertita in UTF16 prima di essere trasmessa. Quando una stringa viene ricevuta, viene convertita da UTF16 a UTF8 se annotata utf8InCpp.

VintfStability

VintfStability dichiara che un tipo definito dall'utente (interfaccia, Parcelable ed enum) può essere utilizzato nei domini di sistema e del fornitore. Consulta il documento AIDL per gli HAL per ulteriori informazioni sull'interoperabilità dei fornitori di sistema.

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 di sistema.

L'annotazione può essere collegata solo alle dichiarazioni dei tipi definite dall'utente, come mostrato qui:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Quando un tipo è annotato con VintfStability, anche qualsiasi altro tipo a cui si fa riferimento nel tipo deve essere annotato come tale. Nell'esempio seguente, Data e IBar devono essere entrambi 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 creati solo utilizzando il tipo di modulo Presto aidl_interface, con la proprietà stability impostata su "vintf".

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

Utilizzo di app non supportato

L'annotazione UnsupportedAppUsage indica che il tipo AIDL annotato fa parte dell'interfaccia non SDK accessibile per le app legacy. Consulta la pagina Restrizioni relative alle interfacce non SDK per ulteriori informazioni sulle API nascoste.

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 è un'operazione autonoma per i backend non Java.

Supporto

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

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

Nel backend CPP, emette una classe enum C++ di tipo int32_t.

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

Se l'annotazione viene omessa, si presume che type sia byte, che viene mappato a int8_t per il backend CPP.

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

  • byte (larghezza di 8 bit)
  • int (larghezza a 32 bit)
  • long (larghezza a 64 bit)

NdkOnlyStableParcelable

NdkOnlyStableParcelable contrassegna una dichiarazione "parcelable" (non definizione) come stabile, in modo che sia possibile farvi riferimento da altri tipi di AIDL stabili. Questo è simile a JavaOnlyStableParcelable, ma NdkOnlyStableParcelable contrassegna una dichiarazione Parcelable come stabile per il backend NDK anziché per Java.

Per utilizzare questa particella:

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

Pacchetti disponibili solo Java

JavaOnlyStableParcelable contrassegna una dichiarazione "parcelable" (non definizione) come stabile, in modo che sia possibile farvi riferimento da altri tipi di AIDL stabili.

Il modello AIDL stabile richiede che tutti i tipi definiti dall'utente siano stabili. Per quanto riguarda i dati catastali, la stabilità richiede che i campi siano descritti esplicitamente 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 era non strutturato (o appena dichiarato), non è possibile fare riferimento.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable ti consente di eseguire l'override del controllo quando il pacchetto a cui fai riferimento è già disponibile al sicuro come parte dell'SDK per Android.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

Estrazione Java

JavaDerive genera automaticamente metodi per i tipi "parcelabili" nel backend Java.

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

L'annotazione richiede parametri aggiuntivi per controllare i dati da 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 i campi. Ad esempio: Data{number: 42, str: foo}

Predefinito di Java

L'elemento JavaDefault, aggiunto in Android 13, consente di stabilire se generare o meno il supporto del controllo delle versioni dell'implementazione predefinita (per setDefaultImpl). Questo supporto non viene più generato per impostazione predefinita per risparmiare spazio.

JavaPassthrough

JavaPassthrough consente all'API Java generata di essere annotata con un'annotazione Java arbitraria.

Le seguenti annotazioni in AIDL

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

diventare

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

nel codice Java generato.

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 di Java, questo non viene rilevato dal compilatore AIDL, ma dal compilatore Java.

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

Dimensioni fisse

FixedSize contrassegna un elemento "parcelable" strutturato come dimensione fissa. Una volta contrassegnato, non sarà più possibile aggiungervi nuovi campi. Tutti i campi del componente "parcelable" devono anche avere tipi di dimensioni fisse, inclusi i tipi primitivi, enum, array a dimensione fissa e altri elementi parcelable contrassegnati con FixedSize.

Questa soluzione non fornisce alcuna garanzia per i diversi bit e non deve essere utilizzata per le comunicazioni con bit vari.

Descrittore

Descriptor specifica in modo forzato il descrittore di un'interfaccia.

package android.foo;

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

Il descrittore di questa interfaccia è android.bar.IWorld. Se manca l'annotazione Descriptor, il descrittore sarà android.foo.IHello.

Ciò è utile per rinominare un'interfaccia già pubblicata. Se il descrittore dell'interfaccia rinominata è uguale al descrittore dell'interfaccia prima della ridenominazione, le due interfacce possono comunicare tra loro.

@nascondi nei commenti

Il compilatore AIDL riconosce @hide nei commenti e lo passa all'output Java, in modo che metalava possa essere prelevato. Questo commento garantisce che il sistema di compilazione di Android sappia 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 dovrebbe più essere utilizzata.

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

Ogni backend contrassegna entità deprecate con un'annotazione o un attributo specifico del backend in modo che il codice client riceva un avviso se fa riferimento a entità deprecate. Ad esempio, l'annotazione @Deprecated e il tag @deprecated sono collegati al codice generato da Java.