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 è allegata all'entità che la segue.

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

@AnnotationName AidlEntity

Queste annotazioni non sono le stesse annotazioni Java, sebbene sembrino molto simili. Gli utenti non possono definire annotazioni AIDL personalizzate; le annotazioni sono tutte predefinite. Alcune annotazioni riguardano 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
NdkOnlyStableParcelable 14
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

nullabile

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

Questa annotazione può essere allegata solo ai tipi restituiti del metodo, ai parametri del metodo e ai campi parcellabili.

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 allegate ai 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 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 è sempre mappato su std::optional<T> .

Per un tipo L simile a un elenco 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 è no-op. In altre parole, sia @nullable IBinder che IBinder si mappano equamente su android::sp<IBinder> , che è già annullabile perché è un puntatore forte (le letture CPP applicano ancora l'annullamento, ma il tipo è ancora android::sp<IBinder> ).

A partire da Android 13, @nullable(heap=true) può essere utilizzato per i campi parcellabili per modellare tipi ricorsivi. @nullable(heap=true) non può essere utilizzato con parametri di metodo o tipi restituiti. Quando annotato con esso, il campo viene mappato su 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 non è operativa per altri backend. Nello specifico, 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 parcellabili.

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

Si noti che l'esistenza dell'annotazione utf8InCpp non modifica il modo in cui le stringhe vengono trasmesse in rete. Le stringhe vengono sempre trasmesse come UTF16 via cavo. Una stringa annotata utf8InCpp viene convertita in UTF16 prima di essere trasmessa. Quando viene ricevuta una stringa, 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 nei domini del sistema e del fornitore. Per ulteriori informazioni sull'interoperabilità tra fornitori di sistemi, vedere AIDL per HAL .

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 i processi del fornitore e del sistema.

L'annotazione può essere allegata solo alle dichiarazioni di tipo definito 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 dovrebbero 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 aidl_interface Soong, con la proprietà stability impostata su "vintf" .

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

Utilizzo app non supportato

L'annotazione UnsupportedAppUsage indica che il tipo AIDL annotato fa parte dell'interfaccia non SDK accessibile per le app legacy. Consulta Restrizioni sulle 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 operazione non è consentita per i backend non Java.

Supporto

L'annotazione Backing specifica il tipo di archiviazione di un tipo di enumerazione 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 presuppone che il type sia byte , che corrisponde a int8_t per il backend CPP.

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

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

NdkOnlyStableParcelable

NdkOnlyStableParcelable contrassegna una dichiarazione parcellabile (non una definizione) come stabile in modo che sia possibile farvi riferimento da altri tipi AIDL stabili. È come JavaOnlyStableParcelable , ma NdkOnlyStableParcelable contrassegna una dichiarazione parcelable come stabile per il backend NDK anziché per Java.

Per utilizzare questo parcelable: * È necessario specificare ndk_header . * È necessario disporre di 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_* , utilizzare static_libs o shared_libs . Per aidl_interface , aggiungi la libreria in additional_shared_libraries in Android.bp .

JavaOnlyStableParcelable

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

L'AIDL stabile richiede che tutti i tipi definiti dall'utente siano stabili. Per i parcelables, essere stabili richiede che i suoi campi siano esplicitamente descritti 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 non era strutturato (o semplicemente dichiarato), non è possibile fare riferimento ad esso.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

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

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive genera automaticamente metodi per tipi parcellabili 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 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

JavaDefault , aggiunto in Android 13, controlla se viene generato 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 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 annotation viene emesso direttamente. Il compilatore AIDL non esamina il valore del parametro. Se è presente un errore di sintassi a livello Java, non verrà rilevato dal compilatore AIDL ma dal compilatore Java.

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

Taglia unica

FixedSize contrassegna un oggetto parcellabile strutturato come dimensione fissa. Una volta contrassegnato, al parcelable non sarà consentito aggiungere nuovi campi. Anche tutti i campi del parcelable devono essere di tipo a dimensione fissa, inclusi i tipi primitivi, le enumerazioni, gli array a dimensione fissa e altri parcelable contrassegnati con FixedSize .

Ciò non fornisce alcuna garanzia tra bit diversi e non dovrebbe essere utilizzato per comunicazioni a bit misti.

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 precedente è android.bar.IWorld . Se manca l'annotazione Descriptor , 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 affinché metalava possa prelevarlo. Questo commento garantisce che il sistema di compilazione 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();
}

Ogni backend contrassegna le entità deprecate con un'annotazione/attributo specifico del backend 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.