Google 致力于为黑人社区推动种族平等。查看具体举措

以 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
JavaOnlyStableParcelable 11
JavaPassthrough S
FixedSize S
Descriptor S

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 S 或更高版本中会映射到 std::optional<T>

在 NDK 后端,@nullable T 始终映射到 std::optional<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 为空操作。换言之,@nullable IBinderIBinder 都会映射到 android::sp<IBinder>(已为 nullable,因为它是强指针)。

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

Hide

Hide 注释类似于 UnsupportedAppUsage。它会直接映射到 Java 注释 android.annotation.Hide,表示某 API 不属于 Android API。

android.annotation.Hide 注释是隐藏 API 的另一种方式,通常通过在 API 注释中的某个位置添加 @hide 字符串字面量来实现。

在非 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 位宽)

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 parceable

parcelable AnotherData {
    Data d; // Error
}

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

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // Ok
}

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

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

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