AIDL 支持注解,这些注解为 AIDL 编译器提供关于带注解元素的额外信息,这也会影响生成的桩代码。
语法与 Java 的语法类似
@AnnotationName(argument1=value, argument2=value) AidlEntity
在此,AnnotationName
是注解的名称,而 AidlEntity
是 AIDL 实体,例如 interface Foo
、void method()
或 int arg
。注解会附加到紧随其后的实体。
某些注解可以设置括号内的参数,如上所示。不带参数的注解不需要括号。例如
@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>
。
在 Rust 后端中,@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>>>
)。
此映射有一个例外。当 T
为 IBinder
或 AIDL 接口时,对于除 Rust 以外的所有后端,@nullable
均不起作用。换句话说,@nullable IBinder
和 IBinder
同样都映射到 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。
此注解可以附加到可以使用 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
进行注解时,类型中引用的任何其他类型也应使用此注解进行注解。在以下示例中,Data
和 IBar
都应使用 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 文件只能使用 aidl_interface
Soong 模块类型进行构建,并且 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
将 parcelable 声明标记为对于 NDK 后端稳定,而不是对于 Java 稳定。
要使用此 parcelable,
- 您必须指定
ndk_header
。 - 您必须有一个 NDK 库指定 parcelable,并且该库必须编译到库中。例如,在
cc_*
模块上的核心构建系统中,使用static_libs
或shared_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
生成equals
和hashCode
方法。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)")
变为
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
在生成的 Java 代码中。
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.net.cn。
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 生成的代码。