AIDL でのアノテーション

AIDL は、アノテーションを付けた要素に関する詳細情報を AIDL コンパイラに提供するアノテーションをサポートしています。これは生成されたスタブコードにも影響します。

この構文は Java の構文に似ています。

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

ここで、AnnotationName はアノテーションの名前で、AidlEntityinterface Foovoid method()int arg などの AIDL エンティティです。その後のエンティティにはアノテーションが付けられます。

上記のように、一部のアノテーションではかっこ内に引数を設定できます。引数のないアノテーションでは、かっこは不要です。次に例を示します。

@AnnotationName AidlEntity

これらのアノテーションは Java アノテーションとよく似ていますが、同じではありません。ユーザーはカスタム AIDL アノテーションを定義できません。アノテーションはすべて事前定義されています。一部のアノテーションは特定のバックエンドのみに影響し、他のバックエンドには影響しません。それらのアノテーションには、付加できる場所に関する別の制限があります。

事前定義されている AIDL AIDL アノテーションのリストを次に示します。

アノテーション 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

nullable

nullable は、アノテーションが付けられたエンティティの値を指定できない場合があることを宣言します。

このアノテーションは、メソッドの戻り値の型、メソッド パラメータ、Parcelable フィールドだけに付加できます。

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

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

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

アノテーションはプリミティブ型には付加できません。次に示すのはエラーです。

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

このアノテーションは Java バックエンドには影響しません。これは、Java では非プリミティブ型はすべて参照によって渡されるためです(null である場合があります)。

CPP バックエンドの場合、@nullable T は Android 11 以下では std::unique_ptr<T> にマッピングされ、Android 12 以降では std::optional<T> にマッピングされます。

NDK バックエンドでは、@nullable T は常に std::optional<T> にマッピングされます。

Rust バックエンドでは、@nullable T は常に Option<T> にマッピングされます。

T[]List<T> のような list-like 型の L の場合、@nullable Lstd::optional<std::vector<std::optional<T>>> にマッピングされます(Android 11 以下の CPP バックエンドの場合は std::unique_ptr<std::vector<std::unique_ptr<T>>>)。

このマッピングには例外があります。TIBinder または AIDL インターフェースの場合、@nullable はどのバックエンドにも影響しません(Rust を除く)。つまり、@nullable IBinderIBinder はどちらも android::sp<IBinder> にマッピングされますが、すでに null 値を許容できます。これは、強いポインタであるためです(CPP 読み取りは引き続き null 可能性を適用しますが、型は android::sp<IBinder> のままです)。Rust では、これらの型は @nullable のアノテーションが付けられている場合にのみ、nullable になります。アノテーションが付けられている場合、Option<T> にマッピングされます。

Android 13 以降では、@nullable(heap=true) を Parcelable フィールドに使用して、再帰型をモデル化できます。@nullable(heap=true) は、メソッド パラメータや戻り値の型と一緒には使用できません。アノテーションが付けられると、このフィールドは CPP/NDK バックエンドのヒープ割り当て参照 std::unique_ptr<T> にマッピングされます。@nullable(heap=true) は Java バックエンドには影響しません。

utf8InCpp

utf8InCpp は、String を CPP バックエンドに対して UTF8 形式で表すことを宣言します。名前が示すように、このアノテーションは他のバックエンドには影響しません。具体的には、String は常に Java バックエンドでは UTF16、NDK バックエンドでは UTF8 です。

このアノテーションは、戻り値、パラメータ、定数宣言、Parcelable フィールドなど、String 型が使用されている任意の場所に付加できます。

CPP バックエンドの場合、AIDL の @utf8InCpp Stringstd::string にマッピングされ、アノテーションなしの String は、UTF16 が使用される android::String16 にマッピングされます。

utf8InCpp アノテーションが存在しても、文字列が送信される方法は変わりません。文字列は常に UTF16 として送信されます。utf8InCpp アノテーション付きの文字列は、送信前に UTF16 に変換されます。受け取った文字列に utf8InCpp のアノテーションが付いていた場合、UTF16 から UTF8 に変換されます。

VintfStability

VintfStability は、システムとベンダーのドメインでユーザー定義型(インターフェース、Parcelable、enum)を使用できることを宣言します。システムとベンダー間の相互運用性の詳細については、HAL 用の AIDL をご覧ください。

アノテーションが型の署名を変更することはありませんが、署名が設定されている場合は、ベンダー プロセスとシステム プロセス間を移動できるように、型のインスタンスが安定版としてマークされます。

以下に示すように、アノテーションはユーザー定義型の宣言だけに付加できます。

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

ある型に VintfStability アノテーションを付ける場合、その型で参照される他の型にも同様にアノテーションを付ける必要があります。以下の例では、DataIBar の両方に 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 {...}

また、VintfStability アノテーション付きの型を定義する AIDL ファイルを作成するには、stability プロパティを "vintf" に設定した aidl_interface Soong モジュール型を使用する必要があります。

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

UnsupportedAppUsage

UnsupportedAppUsage アノテーションは、アノテーション付き AIDL 型が、従来のアプリでアクセス可能な SDK 以外のインターフェースの一部であることを示します。非表示の API について詳しくは、非 SDK インターフェースの制限をご覧ください。

UnsupportedAppUsage アノテーションは、生成されたコードの動作には影響しません。このアノテーションは、生成された Java クラスに、同じ名前の Java アノテーションを付けるだけです。

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

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

これは、Java 以外のバックエンドには影響しません。

Backing

Backing アノテーションは、AIDL 列挙型のストレージ タイプを指定します。

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

CPP バックエンドでは、このように指定すると、int32_t 型の C++ 列挙型クラスが出力されます。

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

アノテーションを省略すると、typebyte とみなされ、CPP バックエンドの int8_t にマッピングされます。

type 引数は、次の整数型だけに設定できます。

  • byte(8 ビット幅)
  • int(32 ビット幅)
  • long(64 ビット幅)

NdkOnlyStableParcelable

NdkOnlyStableParcelable は、他の安定版 AIDL 型から参照できるように、Parcelable 宣言を(定義ではなく)安定版としてマークします。これは JavaOnlyStableParcelable と似ていますが、NdkOnlyStableParcelable は Java ではなく NDK バックエンドの Parcelable 宣言を安定版としてマークします。

この Parcelable を使用するには:

  • ndk_header を指定する必要があります。
  • Parcelable を指定する NDK ライブラリが必要です。このライブラリはライブラリにコンパイルする必要があります。たとえば、cc_* モジュールのコア ビルドシステムでは、static_libs または shared_libs を使用します。aidl_interface については、Android.bpadditional_shared_libraries にライブラリを追加します。

JavaOnlyStableParcelable

JavaOnlyStableParcelable は、他の安定版 AIDL 型から参照できるように、Parcelable 宣言を(定義ではなく)安定版としてマークします。

安定版 AIDL では、すべてのユーザー定義型が安定版である必要があります。Parcelable の場合、安定版にするには、フィールドを 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
}

Parcelable が構造化されていない(宣言されたばかりである)場合は参照できません。

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable を使用すると、参照する Parcelable が Android SDK の一部として安全に使用可能になったときにチェックをオーバーライドできます。

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive は、Java バックエンドの Parcelable 型のメソッドを自動的に生成します。

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

アノテーションには、何を生成するかを制御するための追加のパラメータが必要です。現在サポートされているパラメータは次のとおりです:

  • equals=true は、equals メソッドと hashCode メソッドを生成します。
  • toString=true は、型とフィールドの名前を出力する toString メソッドを生成します。(例: Data{number: 42, str: foo})。

JavaDefault

Android 13 で追加された JavaDefault は、デフォルトの実装バージョニング サポートを生成するかどうかを制御します(setDefaultImpl 用)。スペース節約のために、このサポートはデフォルトで生成されなくなりました。

JavaPassthrough

JavaPassthrough を使用すると、生成された Java API に任意の Java アノテーションを付けることができます。

次に示す AIDL のアノテーションは

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

生成された Java コードで

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

このようになります。

annotation パラメータの値は直接出力されます。AIDL コンパイラはパラメータの値については考慮しません。Java レベルの構文エラーがある場合、これは AIDL コンパイラではなく Java コンパイラによって捕捉されます。

このアノテーションは、任意の AIDL エンティティに付加できます。Java 以外のバックエンドには影響しません。

FixedSize

FixedSize は、構造化された Parcelable を固定サイズとしてマークします。一度指定すると、Parcelable に新しいフィールドを追加できなくなります。また、Parcelable のすべてのフィールドは、プリミティブ型、列挙型、固定サイズ配列、FixedSize でマークされた他の Parcelable など、サイズが固定された型でなければなりません。

ただし、ビットが異なる場合については保証されないため、ビットが混在する通信ではこの方法に依存しないでください。

Descriptor

Descriptor は、インターフェースのインターフェース記述子を強制的に指定します。

package android.foo;

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

このインターフェースの記述子は android.bar.IWorld です。Descriptor アノテーションがない場合、記述子は android.foo.IHello になります。

これは、公開済みのインターフェースの名前を変更する場合に役立ちます。名前を変更したインターフェースの記述子を、名前を変更する前のインターフェースの記述子と同じにすると、2 つのインターフェースが相互に通信できるようになります。

コメント内の @hide

AIDL コンパイラは、コメント内の @hide を認識して Java 出力にこれを渡し、metalava が受け取れるようにします。このコメントにより、AIDL API が SDK API ではないことを Android ビルドシステムが認識できるようになります。

コメント内の @deprecated

AIDL コンパイラは、コメント内の @deprecated をタグとして認識し、使用すべきでない AIDL エンティティを識別します。

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

各バックエンドは、非推奨のエンティティをバックエンド固有のアノテーション / 属性でマークして、非推奨のエンティティを参照する場合にクライアント コードが警告されるようにします。たとえば、@Deprecated アノテーションと @deprecated タグは Java で生成されたコードに付加されます。