以 AIDL 编写的注释

AIDL 支持通过添加注释向 AIDL 编译器提供所注释元素的其他信息,这些信息也会影响生成的桩代码。

其语法类似于 Java 的语法:

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

其中 AnnotationName 为注释的名称,AidlEntityinterface Foovoid method()int arg 等 AIDL 实体。注解会附加到其后面的实体。

如上所示,您可在括号内为某些注释设置参数。注释如果没有参数,就不需要使用括号。例如:

@AnnotationName AidlEntity

虽然这些注释和 Java 注释看起来非常相似,但二者并不相同。用户无法定义自定义 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>

在 NDK 后端,@nullable T 始终映射到 Option<T>

如果是列表式类型 L(例如 T[]List<T>),@nullable L 会映射到 std::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>(已为 nullable,因为它是强指针)(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>。在 Java 后端,@nullable(heap=true) 是空操作。

utf8InCpp

utf8InCpp 声明了 String 会在 CPP 后端用 UTF8 格式表示。顾名思义,该注解在其他后端为空操作。具体而言,String 在 Java 后端始终采用 UTF16 编码格式,在 NDK 后端始终采用 UTF8 编码格式。

此注释可以附加到可使用 String 类型的任何位置,包括返回值、参数、常量声明和 Parcelable 字段。

对于 CPP 后端,AIDL 中的 @utf8InCpp String 会映射到 std::string,而没有注释的 String 会映射到使用 UTF16 编码格式的 android::String16

请注意,utf8InCpp 注释不会影响通过网络传输字符串的方式。字符串将始终作为 UTF16 编码格式通过网络传输。在传输附有 utf8InCpp 注释的字符串之前会将其转换为 UTF16 编码格式。收到某字符串后,如果该字符串附有 utf8InCpp 注释,则会将其从 UTF16 编码格式转换为 UTF8 编码格式。

VintfStability

VintfStability 用于声明可在系统域和供应商域中使用用户定义的类型(接口、Parcelable 及枚举值)。如需详细了解系统域和供应商域之间的互操作性,请参阅适用于 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 {...}

此外,只能使用 aidl_interface Soong 模块类型构建用于定义附有 VintfStability 注释的类型的 AIDL 文件,并将 stability 属性设置为 "vintf"

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,
}

如果省略该注释,type 将被假定为 byte,后者会在 CPP 后端映射到 int8_t

只能将 type 参数设置为以下整数类型:

  • byte(8 位宽)
  • int(32 位宽)
  • long(64 位宽)

NdkOnlyStableParcelable

NdkOnlyStableParcelable 用于将 Parcelable 声明(未定义)标记为“稳定”,以供其他稳定的 AIDL 类型引用。 这与 JavaOnlyStableParcelable 类似,但 NdkOnlyStableParcelable 用于针对 NDK 后端(而非 Java)将 Parcelable 声明“稳定”。

如需使用此 Parcelable,请执行以下操作:

  • 您必须指定 ndk_header
  • 您必须有一个用于指定 Parcelable 的 NDK 库,且必须将该库编译到内容库中。例如,在核心构建系统内的 cc_* 模块中,使用 static_libsshared_libs。对于 aidl_interface,请在 Android.bp 中的 additional_shared_libraries 下添加库。

JavaOnlyStableParcelable

JavaOnlyStableParcelable 用于将 Parcelable 声明(未定义)标记为“稳定”,以供其他稳定的 AIDL 类型引用。

稳定的 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
}

如果您正在引用的 Parcelable 已作为 Android SDK 的一部分安全提供,您可借助 JavaOnlyStableParcelable 替代检查操作。

@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 会生成 equalshashCode 方法。
  • toString=true 会生成 toString 方法,用于输出类型和字段的名称。例如:Data{number: 42, str: foo}

JavaDefault

Android 13 中添加了 JavaDefault,用于控制是否针对 setDefaultImpl 生成默认实现版本控制支持。为了节省空间,系统不再默认生成此支持。

JavaPassthrough

JavaPassthrough 允许使用任意 Java 注解对生成的 Java API 进行注解。

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 后端,该注释为空操作。

RustDerive

RustDerive 会自动为生成的 Rust 类型实现特征。

此注解需要其他参数来控制要生成的内容。支持的参数包括:

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

如需了解这些特征的说明,请参阅 https://doc.rust-lang.org。

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

该注释在重命名已发布的接口时非常有用。如果描述符在接口重命名前后保持不变,重命名前后的两个接口便可相互通信。

注释中的 @hide

AIDL 编译器可识别注释中的 @hide 并将其传递给 Java 输出,以便 Metalava 提取数据。此注释可确保 Android 构建系统知道 AIDL API 并非 SDK API。

注释中的 @deprecated

AIDL 编译器会将注释中的 @deprecated 识别为标记,以确定不应再使用的 AIDL 实体。

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

每个后端都使用特定于后端的注释或属性标记已废弃的实体,以便客户端代码在引用已废弃的实体时收到警告。例如,@Deprecated 注释和 @deprecated 标记会附加到 Java 生成的代码。