Anmerkungen in AIDL

AIDL unterstützt Anmerkungen, die dem AIDL-Compiler zusätzliche Informationen zum kommentierten Element geben, was sich auch auf den generierten Stub-Code auswirkt.

Die Syntax ähnelt der von Java:

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

Dabei ist AnnotationName der Name der Annotation und AidlEntity eine AIDL-Entität wie interface Foo, void method() oder int arg. Eine Anmerkung wird der nachfolgenden Einheit zugeordnet.

Für einige Anmerkungen können Argumente in den Klammern festgelegt werden, wie im vorherigen Beispiel gezeigt. Bei Hinweisen ohne Argumente sind die Klammern nicht erforderlich. Beispiel:

@AnnotationName AidlEntity

Diese Anmerkungen sind nicht mit den Java-Anmerkungen identisch, obwohl sie ähnlich aussehen. Alle Anmerkungen sind vordefiniert und haben Einschränkungen hinsichtlich der Stellen, an denen Sie sie anbringen können. Einige Anmerkungen wirken sich nur auf ein bestimmtes Backend aus und sind in anderen Backends ein No-Op.

Hier ist die Liste der vordefinierten AIDL-Annotationen:

AnnotationenIn Android-Version hinzugefügt
nullable7
utf8InCpp7
VintfStability11
UnsupportedAppUsage10
Hide11
Backing11
NdkOnlyStableParcelable14
JavaOnlyStableParcelable11
JavaDerive12
JavaPassthrough12
FixedSize12
Descriptor12

nullable

nullable deklariert, dass der Wert der annotierten Entität null sein kann.

Sie können diese Annotation nur an Methodenrückgabetypen, Methodenparameter und Parcelable-Felder anhängen:

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

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

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

Annotationen können nicht an primitive Typen angehängt werden. Das Folgende ist ein Fehler:

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

Diese Annotation hat keine Auswirkungen auf das Java-Backend. In Java werden alle nicht primitiven Typen als Referenz übergeben, was null sein könnte.

Im CPP-Backend wird @nullable T in Android 11 oder niedriger std::unique_ptr<T> und in Android 12 oder höher std::optional<T> zugeordnet.

Im NDK-Backend wird @nullable T std::optional<T> zugeordnet.

Im Rust-Backend wird @nullable T auf Option<T> abgebildet.

Bei einem listenähnlichen Typ L wie T[] oder List<T> wird @nullable L std::optional<std::vector<std::optional<T>>> zugeordnet (oder std::unique_ptr<std::vector<std::unique_ptr<T>>> im Fall des CPP-Back-Ends für Android 11 oder niedriger).

Es gibt eine Ausnahme von dieser Zuordnung. Wenn T IBinder oder eine AIDL-Schnittstelle ist, ist @nullable ein No-Op für die Java-, CPP- und NDK-Backends. Im CPP-Backend werden beispielsweise sowohl @nullable IBinder als auch IBinder gleichermaßen android::sp<IBinder> zugeordnet. android::sp<IBinder> ist bereits null-zulässig, da es sich um einen starken Zeiger handelt. Bei CPP- und NDK-Lesevorgängen wird weiterhin die Null-Zulässigkeit erzwungen, der Typ bleibt jedoch android::sp<IBinder> oder ndk::SpAIBinder.

Im Rust-Backend werden Typen, die Default nicht implementieren (IBinder, AIDL-Schnittstellen, ParcelFileDescriptor und unstrukturierte Parcelables), je nach Kontext auf Option<T> abgebildet:

  • Methodenrückgabetypen, in-Parameter und inout-Parameter:Diese Typen sind nur dann nullable, wenn sie mit @nullable annotiert sind. Sie werden dann Option<T> zugeordnet (oder Option<&T> für in-Parameter und &mut Option<T> für inout-Parameter). Ohne @nullable werden sie direkt T (oder &T und &mut T) zugeordnet.
  • Parcelable-Felder und out-Parameter:Da abgeleitete Parcelables in Rust Default und out-Parameter standardmäßig initialisiert werden, werden diese Typen immer Option<T> zugeordnet (und Arrays mit fester Größe in diesen Kontexten werden [Option<T>; N] zugeordnet, während dynamische Arrays in out-Parametern Vec<Option<T>> zugeordnet werden), auch ohne @nullable. Wenn sie nicht mit @nullable annotiert sind, wird die Nicht-Null-Eigenschaft zur Laufzeit während des Parceling weiterhin erzwungen (StatusCode::UNEXPECTED_NULL wird zurückgegeben, wenn der Wert None ist).

Ab Android 13 kann @nullable(heap=true) für parcelable-Felder verwendet werden, um rekursive Typen zu modellieren. @nullable(heap=true) kann nicht mit Methodenparametern oder Rückgabetypen verwendet werden. Wenn das Feld damit annotiert ist, wird es im CPP- und NDK-Backend einer heap-zugeordneten Referenz std::unique_ptr<T> zugeordnet. @nullable(heap=true) ist im Java-Backend ein No-Op.

utf8InCpp

utf8InCpp deklariert, dass String für das CPP-Backend im UTF8-Format dargestellt wird. Wie der Name schon sagt, ist die Annotation für andere Backends ein No-Op. Insbesondere ist String im Java-Backend immer UTF16 und im NDK-Backend UTF8.

Diese Annotation kann überall angehängt werden, wo der Typ String verwendet werden kann, einschließlich Rückgabewerten, Parametern, Konstantendeklarationen und Parcelable-Feldern.

Im CPP-Backend wird @utf8InCpp String in AIDL std::string zugeordnet. Dabei wird String ohne die Annotation android::String16 zugeordnet, wobei UTF16 verwendet wird.

VintfStability

VintfStability deklariert, dass ein benutzerdefinierter Typ (Schnittstelle, Parcelable und Enum) system- und anbieterübergreifend verwendet werden kann. Weitere Informationen zur Interoperabilität zwischen System und Anbieter finden Sie unter AIDL für HALs.

Die Annotation ändert die Signatur des Typs nicht. Wenn sie jedoch festgelegt ist, wird die Instanz des Typs als stabil markiert, sodass sie zwischen den Anbieter- und Systemprozessen übertragen werden kann.

Die Anmerkung kann nur an benutzerdefinierte Typdeklarationen angehängt werden, wie hier gezeigt:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Wenn ein Typ mit VintfStability annotiert ist, sollte jeder andere Typ, auf den im Typ verwiesen wird, ebenfalls so annotiert werden. Im folgenden Beispiel sollten sowohl Data als auch IBar mit VintfStability annotiert werden:

@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 {...}

Außerdem können die AIDL-Dateien, die mit VintfStability annotierte Typen definieren, nur mit dem Soong-Modultyp aidl_interface erstellt werden, wobei die Eigenschaft stability auf vintf gesetzt ist:

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

UnsupportedAppUsage

Die Annotation UnsupportedAppUsage gibt an, dass der annotierte AIDL-Typ Teil der Nicht-SDK-Schnittstelle ist, die für Legacy-Apps zugänglich war. Weitere Informationen zu den verborgenen APIs finden Sie unter Einschränkungen für Nicht-SDK-Schnittstellen.

Die Annotation UnsupportedAppUsage hat keine Auswirkungen auf das Verhalten des generierten Codes. Die Annotation annotiert nur die generierte Java-Klasse mit der gleichnamigen Java-Annotation:

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

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

Für Nicht-Java-Back-Ends ist dies ein No-Op.

Hinweis zur Sicherung

Mit der Annotation Backing wird der Speichertyp eines AIDL-Enum-Typs angegeben:

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

Im CPP-Backend wird dadurch eine C++-Enum-Klasse vom Typ int32_t ausgegeben:

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

Wird die Anmerkung weggelassen, wird type als byte angenommen, was für das CPP-Backend int8_t entspricht.

Das Argument type kann nur auf die folgenden integralen Typen festgelegt werden:

  • byte (8 Bit breit)
  • int (32 Bit breit)
  • long (64 Bit breit)

NdkOnlyStableParcelable

NdkOnlyStableParcelable kennzeichnet eine Parcelable-Deklaration (nicht Definition) als stabil, sodass darauf von anderen stabilen AIDL-Typen verwiesen werden kann. Dies entspricht JavaOnlyStableParcelable, aber NdkOnlyStableParcelable kennzeichnet eine Parcelable-Deklaration als stabil für das NDK-Backend anstelle von Java.

So verwenden Sie dieses Parcelable:

  • Sie müssen ndk_header angeben.
  • Sie benötigen eine NDK-Bibliothek, in der das Parcelable angegeben ist. Die Bibliothek muss in die Bibliothek kompiliert werden. Verwenden Sie beispielsweise im Core-Build-System für ein cc_*-Modul static_libs oder shared_libs. Fügen Sie für aidl_interface die Bibliothek unter additional_shared_libraries in Android.bp hinzu.

JavaOnlyStableParcelable

JavaOnlyStableParcelable kennzeichnet eine Parcelable-Deklaration (nicht Definition) als stabil, sodass darauf von anderen stabilen AIDL-Typen verwiesen werden kann.

Für stabiles AIDL müssen alle benutzerdefinierten Typen stabil sein. Bei Parcelables muss die Stabilität durch eine explizite Beschreibung der Felder in der AIDL-Quelldatei gewährleistet werden:

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
}

Wenn das Parcelable unstrukturiert ist (oder nur deklariert wurde), kann nicht darauf verwiesen werden:

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

Mit JavaOnlyStableParcelable können Sie die Prüfung überschreiben, wenn das Parcelable, auf das Sie verweisen, sicher als Teil des Android SDK verfügbar ist:

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive generiert automatisch Methoden für Parcelable-Typen im Java-Backend:

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

Für die Anmerkung sind zusätzliche Parameter erforderlich, um zu steuern, was generiert werden soll. Folgende Parameter werden unterstützt:

  • equals=true generiert die Methoden equals und hashCode.
  • toString=true generiert die Methode toString, die den Namen des Typs und der Felder ausgibt, z. B. Data{number: 42, str: foo}.

JavaDefault (eingestellt)

JavaDefault, die in Android 13 hinzugefügt wurde, steuert, ob die Standardimplementierungsversionsverwaltung für setDefaultImpl generiert wird. Diese Unterstützung wird nicht mehr standardmäßig generiert, um Speicherplatz zu sparen.

JavaPassthrough

Mit JavaPassthrough kann die generierte Java API mit einer beliebigen Java-Annotation annotiert werden.

Diese Anmerkungen in AIDL:

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

werden im generierten Java-Code zu:

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

Der Wert des Parameters annotation wird direkt ausgegeben. Der AIDL-Compiler prüft den Wert des Parameters nicht. Syntaxfehler auf Java-Ebene werden nicht vom AIDL-Compiler, sondern vom Java-Compiler erkannt.

Diese Annotation kann an jede AIDL-Entität angehängt werden. Diese Annotation hat keine Auswirkungen auf Backends, die nicht auf Java basieren.

RustDerive

RustDerive implementiert automatisch Traits für generierte Rust-Typen.

Für die Anmerkung sind zusätzliche Parameter erforderlich, um zu steuern, was generiert werden soll. Folgende Parameter werden unterstützt:

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

Erläuterungen zu diesen Merkmalen finden Sie in der Rust-Dokumentation.

FixedSize

FixedSize kennzeichnet ein strukturiertes Parcelable als feste Größe. Nachdem das Parcelable markiert wurde, können Sie keine neuen Felder mehr hinzufügen. Alle Felder des Parcelable-Objekts müssen Typen mit fester Größe sein, einschließlich primitiver Typen, Enums, Arrays mit fester Größe und anderer Parcelable-Objekte, die mit FixedSize gekennzeichnet sind.

FixedSize-Objekte haben stabile Größen und Ausrichtungen im ndk-Backend.

Typ Größe (Byte) Ausrichtung (Byte)
boolean 1 1
byte 1 1
char 2 2
int 4 4
long 8 8
float 4 4
double 8 8
parcelable Gesamtgröße aller Felder Größte Ausrichtung aller Felder
union Größte Größe aller Felder Größte Ausrichtung aller Felder
enum Größe des Sicherungstyps Ausrichtung des Backing-Typs
T[N] (Array mit fester Größe) Größe von T * N Abstimmung von T
String, IBinder, FileDescriptor, ParcelFileDescriptor N/A N/A

Deskriptor

Descriptor gibt den Schnittstellendeskriptor einer Schnittstelle an:

package android.foo;

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

Der Deskriptor dieser Schnittstelle ist android.bar.IWorld. Wenn die Anmerkung Descriptor fehlt, lautet der Deskriptor android.foo.IHello.

Das ist nützlich, um eine bereits veröffentlichte Schnittstelle umzubenennen. Wenn Sie den Deskriptor der umbenannten Schnittstelle mit dem Deskriptor der Schnittstelle vor der Umbenennung identisch machen, können die beiden Schnittstellen miteinander kommunizieren.

@hide in comments

Der AIDL-Compiler erkennt @hide in Kommentaren und gibt sie an die Java-Ausgabe weiter, damit Metalava sie aufnehmen kann. Dieser Kommentar sorgt dafür, dass das Android-Build-System erkennt, dass AIDL-APIs keine SDK-APIs sind.

@deprecated in Kommentaren

Der AIDL-Compiler erkennt @deprecated in Kommentaren als Tag, um eine AIDL-Entität zu identifizieren, die nicht mehr verwendet werden sollte:

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

Jedes Backend kennzeichnet eingestellte Entitäten mit einer backend-spezifischen Annotation oder einem Attribut, sodass der Clientcode gewarnt wird, wenn er auf die eingestellten Entitäten verweist. Die Annotation @Deprecated und das Tag @deprecated sind beispielsweise an den generierten Java-Code angehängt.