Annotationen in AIDL

AIDL unterstützt Anmerkungen, die dem AIDL-Compiler zusätzliche Informationen zum annotierten Element liefern. Dies wirkt sich auch auf den generierten Stub-Code aus.

Die Syntax ähnelt der von Java:

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

Hier ist AnnotationName der Name der Anmerkung und AidlEntity ist eine AIDL-Entität wie interface Foo, void method() oder int arg. Eine Anmerkung wird an die darauffolgende Entität angehängt.

Einige Anmerkungen können Argumente in den Klammern haben, wie oben gezeigt. Bei Anmerkungen ohne Argument sind keine Klammern erforderlich. Beispiel:

@AnnotationName AidlEntity

Diese Anmerkungen sind nicht mit den Java-Anmerkungen identisch, obwohl sie sehr ähnlich aussehen. Nutzer können keine benutzerdefinierten AIDL-Annotationen definieren. Alle Annotationen sind vordefiniert. Einige Annotationen wirken sich nur auf ein bestimmtes Back-End aus und sind in anderen Back-Ends nicht funktionsfähig. Für sie gelten unterschiedliche Einschränkungen, wo sie angebracht werden können.

Hier ist eine Liste der vordefinierten AIDL-Anmerkungen:

Anmerkungen In der Android-Version hinzugefügt
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
NdkOnlyStableParcelable 14
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

nullable

nullable gibt an, dass der Wert der annotierten Entität möglicherweise nicht angegeben wird.

Diese Anmerkung kann nur an Methodenrückgabetypen, Methodenparameter und parzellierbare Felder angehängt werden.

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

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

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

Anmerkungen können nicht an primitive Typen angehängt werden. Folgendes ist ein Fehler.

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

Diese Anmerkung hat für das Java-Backend keine Auswirkungen. Das liegt daran, dass in Java alle nicht primitiven Typen per Verweis übergeben werden, was null sein könnte.

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

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

Im Rust-Back-End wird @nullable T immer Option<T> zugeordnet.

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

Für diese Zuordnung gibt es eine Ausnahme. Wenn T IBinder oder eine AIDL-Schnittstelle ist, ist @nullable für alle Back-Ends außer Rust eine Null-Operation. Mit anderen Worten: Sowohl @nullable IBinder als auch IBinder werden gleichermaßen auf android::sp<IBinder> abgebildet, das bereits nullable ist, da es sich um einen starken Pointer handelt. Bei C++-Lesevorgängen wird weiterhin die Nullable-Eigenschaft erzwungen, der Typ ist jedoch weiterhin android::sp<IBinder>. In Rust sind diese Typen nur dann nullable, wenn sie mit @nullable annotiert sind. Sie werden Option<T> zugeordnet, wenn sie kommentiert sind.

Ab Android 13 kann @nullable(heap=true) für parzellierbare 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 in den CPP/NDK-Backends einer heap-allozierten Referenz std::unique_ptr<T> zugeordnet. @nullable(heap=true) ist im Java-Backend eine Null-Operation.

utf8InCpp

utf8InCpp gibt an, dass ein String im UTF-8-Format für das CPP-Backend dargestellt wird. Wie der Name schon sagt, hat die Anmerkung für andere Back-Ends keine Auswirkungen. Im Java-Backend ist String immer UTF-16 und im NDK-Backend UTF-8.

Diese Anmerkung kann überall angebracht werden, wo der Typ String verwendet werden kann, einschließlich Rückgabewerten, Parametern, Konstantendeklarationen und Parcelable-Feldern.

Für das CPP-Backend wird @utf8InCpp String in AIDL std::string zugeordnet, während String ohne Anmerkung android::String16 zugeordnet wird, wenn UTF-16 verwendet wird.

Das Vorhandensein der Annotation utf8InCpp hat keinen Einfluss auf die Art und Weise, wie Strings über das Kabel übertragen werden. Strings werden immer als UTF-16 übertragen. Ein mit utf8InCpp annotierter String wird vor der Übertragung in UTF-16 konvertiert. Wenn ein String empfangen wird, wird er von UTF-16 in UTF-8 konvertiert, wenn er als utf8InCpp gekennzeichnet wurde.

vintfStabilität

VintfStability deklariert, dass ein benutzerdefinierter Typ (interface, 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.

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

Die Annotation 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 wird, sollten alle anderen Typen, auf die im Typ verwiesen wird, ebenfalls entsprechend annotiert werden. Im folgenden Beispiel sollten sowohl Data als auch IBar mit VintfStability gekennzeichnet sein.

@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 das Attribut stability auf "vintf" gesetzt ist.

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

UnsupportedAppUsage

Die Annotation UnsupportedAppUsage zeigt an, dass der annotierte AIDL-Typ Teil der Nicht-SDK-Schnittstelle ist, auf die Legacy-Anwendungen Zugriff haben. Weitere Informationen zu den ausgeblendeten APIs finden Sie unter Einschränkungen für Nicht-SDK-Schnittstellen.

Die Annotation UnsupportedAppUsage hat keinen Einfluss auf das Verhalten des generierten Codes. Die Annotation fügt nur der generierten Java-Klasse die Java-Annotation mit demselben Namen hinzu.

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

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

Für andere Back-Ends ist dies nicht erforderlich.

Unterlage

Die Anmerkung Backing gibt den Speichertyp eines AIDL-Enumtyps an.

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

Im CPP-Backend wird dadurch eine C++-Enum-Klasse vom Typ int32_t generiert.

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

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

Das Argument type kann nur auf die folgenden Ganzzahltypen festgelegt werden:

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

NdkOnlyStableParcelable

NdkOnlyStableParcelable kennzeichnet eine Paketdeklaration (keine Definition) als stabil, damit von anderen stabilen AIDL-Typen darauf verwiesen werden kann. Das ist ähnlich wie JavaOnlyStableParcelable, aber NdkOnlyStableParcelable kennzeichnet eine Parcelable-Deklaration als stabil für das NDK-Backend anstelle von Java.

So verwenden Sie diese Parcelable:

  • Sie müssen ndk_header angeben.
  • Sie benötigen eine NDK-Bibliothek, in der das Parcelable angegeben ist, und die Bibliothek muss in die Bibliothek kompiliert werden. Verwenden Sie beispielsweise im Kern-Build-System eines cc_*-Moduls 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 stabile AIDL-Dateien müssen alle benutzerdefinierten Typen stabil sein. Damit Parcelable-Objekte stabil sind, müssen ihre Felder in der AIDL-Quelldatei explizit beschrieben 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 (oder nur deklariert) war, kann es nicht referenziert 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, bereits sicher als Teil des Android SDK verfügbar ist.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive generiert automatisch Methoden für paketbare 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. Beispiel: Data{number: 42, str: foo}

JavaDefault

JavaDefault, in Android 13 hinzugefügt, steuert, ob die Standardimplementierung für die Versionsverwaltung generiert wird (für setDefaultImpl). 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.

Die folgenden Anmerkungen in AIDL

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

werden

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

im generierten Java-Code.

Der Wert des Parameters annotation wird direkt gesendet. Der AIDL-Compiler prüft den Wert des Parameters nicht. Ein Syntaxfehler auf Java-Ebene wird nicht vom AIDL-Compiler, sondern vom Java-Compiler abgefangen.

Diese Anmerkung kann an jede AIDL-Entität angehängt werden. Diese Anmerkung hat für Nicht-Java-Backends keine Auswirkungen.

FixedSize

FixedSize kennzeichnet ein strukturiertes Parcelable als feste Größe. Danach können dem Parcelable keine neuen Felder hinzugefügt werden. Alle Felder des Pakets müssen ebenfalls Typen mit fester Größe haben, einschließlich primitiver Typen, Enums, Arrays mit fester Größe und anderer Parzellen, die mit FixedSize gekennzeichnet sind.

Dies bietet keine Garantie für verschiedene Bits und sollte nicht für eine Kommunikation mit gemischter Bitqualität verwendet werden.

Beschreibung

Descriptor gibt den Interface-Descriptor einer Schnittstelle erzwungen an.

package android.foo;

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

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

Dies ist hilfreich, wenn Sie eine bereits veröffentlichte Schnittstelle umbenennen möchten. Wenn der Deskriptor der umbenannten Schnittstelle mit dem Deskriptor der Schnittstelle vor der Umbenennung übereinstimmt, können die beiden Schnittstellen miteinander kommunizieren.

@hide in comments

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

@deprecated in comments

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

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

Jedes Back-End markiert verworfene Entitäten mit einer Back-End-spezifischen Anmerkung oder einem Back-End-Attribut, sodass der Clientcode gewarnt wird, wenn er auf die verworfenen Entitäten verweist. Beispielsweise werden die Annotation @Deprecated und das Tag @deprecated an den von Java generierten Code angehängt.