Annotazioni in AIDL

AIDL supporta le annotazioni che forniscono al compilatore AIDL ulteriori informazioni 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 . Un'annotazione è allegata all'entità che la segue.

Alcune annotazioni possono avere argomenti tra parentesi, come mostrato sopra. Le annotazioni che non hanno un argomento non necessitano delle parentesi. Per esempio:

@AnnotationName AidlEntity

Queste annotazioni non sono le stesse di Java, anche se sembrano molto simili. Gli utenti non possono definire annotazioni AIDL personalizzate; le annotazioni sono tutte predefinite. Alcune annotazioni interessano solo un determinato backend e non sono operative in altri backend. Hanno diverse restrizioni a cui possono essere collegati.

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

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

nullable

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

Questa annotazione può essere allegata solo ai tipi di restituzione del metodo, ai parametri del metodo e ai campi partizionabili.

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

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

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

Non è possibile allegare annotazioni a tipi primitivi. Quello che segue è un errore.

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

Questa annotazione non è operativa 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 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 sempre il mapping a std::optional<T> .

Per un tipo L simile a un elenco come T[] o List<T> , @nullable L il mapping a std::optional<std::vector<std::optional<T>>> (o std::unique_ptr<std::vector<std::unique_ptr<T>>> in caso di backend CPP per Android 11 o precedenti).

C'è un'eccezione a questa mappatura. Quando T è IBinder o un'interfaccia AIDL, @nullable è no-op. In altre parole, sia @nullable IBinder che IBinder ugualmente mappati su android::sp<IBinder> , che è già nullable perché è un puntatore forte (le letture CPP applicano ancora il nullability, ma il tipo è ancora android::sp<IBinder> ).

A partire da Android T (AOSP sperimentale), @nullable(heap=true) può essere usato per i campi partizionabili per modellare i tipi ricorsivi. @nullable(heap=true) non può essere utilizzato con parametri di metodo o tipi restituiti. Quando viene annotato con esso, il campo viene mappato a un riferimento allocato nell'heap std::unique_ptr<T> nei backend CPP/NDK. @nullable(heap=true) non è operativo nel backend Java.

utf8InCpp

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

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

Per il back-end CPP, @utf8InCpp String in AIDL esegue il mapping su std::string , mentre String senza l'annotazione esegue il mapping su android::String16 dove viene utilizzato UTF16.

Si noti che l'esistenza dell'annotazione utf8InCpp non cambia il modo in cui le stringhe vengono trasmesse sul 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 è stata annotata come utf8InCpp .

VintfStabilità

VintfStability dichiara che un tipo definito dall'utente (interfaccia, parcelable ed enum) può essere utilizzato nel sistema e nei domini dei fornitori. Vedere AIDL per HAL per ulteriori informazioni sull'interoperabilità tra fornitori di sistema.

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

L'annotazione può essere allegata solo a dichiarazioni di tipo definite dall'utente come mostrato di seguito:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Quando un tipo viene 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 compilati solo utilizzando il tipo di modulo aidl_interface Soong, con la proprietà di 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 che è stata accessibile per le app legacy. Per ulteriori informazioni sulle API nascoste, consulta Restrizioni sulle 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 {...}

Questo è un no-op 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, quanto sopra 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 il type sia byte , che esegue il mapping a int8_t per il back-end CPP.

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

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

JavaOnlyStableParcelable

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

L'AIDL stabile richiede che tutti i tipi definiti dall'utente siano stabili. Per i parcelable, essere stabili richiede che i suoi campi siano descritti esplicitamente nel file sorgente 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 destrutturato (o appena dichiarato), allora non può essere referenziato.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable ti consente di ignorare il controllo quando il pacchetto a cui stai facendo riferimento è già disponibile in modo sicuro come parte dell'SDK Android.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDeriva

JavaDerive genera automaticamente i metodi per i tipi partizionabili 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}

JavaPredefinito

JavaDefault , aggiunto in Android T (AOSP sperimentale), controlla se viene generato il supporto per il controllo delle versioni dell'implementazione predefinito (per setDefaultImpl ). Questo supporto non è più generato per impostazione predefinita per risparmiare spazio.

JavaPassthrough

JavaPassthrough consente di annotare l'API Java generata 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 di annotation viene emesso direttamente. Il compilatore AIDL non esamina il valore del parametro. Se è presente un errore di sintassi a livello di Java, non verrà rilevato dal compilatore AIDL ma dal compilatore Java.

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

Taglia unica

FixedSize contrassegna un parcelable strutturato come dimensione fissa. Una volta contrassegnato, al parcelable non sarà consentito aggiungere nuovi campi. Tutti i campi del parcelable devono essere anche tipi di dimensioni fisse, inclusi tipi primitivi, enum, matrici di dimensioni fisse e altri parcelable contrassegnati con FixedSize .

Ciò non fornisce alcuna garanzia su bitness diversi e non dovrebbe essere utilizzato per la comunicazione a bit misto.

Descrittore

Descriptor specifica forzatamente il descrittore di interfaccia di un'interfaccia.

package android.foo;

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

Il descrittore dell'interfaccia sopra è android.bar.IWorld . Se l'annotazione del Descriptor è mancante, il descrittore sarebbe android.foo.IHello .

Ciò è utile per rinominare un'interfaccia già pubblicata. Rendere il descrittore dell'interfaccia rinominata uguale al descrittore dell'interfaccia prima della ridenominazione consente alle due interfacce di comunicare tra loro.

@nascondi nei commenti

Il compilatore AIDL riconosce @hide nei commenti e lo passa all'output Java per il rilevamento di metalava. Questo commento garantisce che il sistema di build Android sappia che le API AIDL non sono API SDK.

@deprecato 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();
}

Ciascun back-end contrassegna le entità deprecate con un'annotazione/attributo specifico del back-end in modo che il codice client venga avvisato se fa riferimento alle entità deprecate. Ad esempio, l'annotazione @Deprecated e il tag @deprecated sono allegati al codice generato da Java.