AIDL 支持通过添加注释向 AIDL 编译器提供所注释元素的其他信息,这些信息也会影响生成的桩代码。
其语法类似于 Java 的语法:
@AnnotationName(argument1=value, argument2=value) AidlEntity
其中 AnnotationName
为注释的名称,AidlEntity
为 interface Foo
、void 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>>>
)。
但也有例外情况。当 T
为 IBinder
或 AIDL 接口时,@nullable
对所有后端(Rust 除外)都是空操作。换言之,@nullable IBinder
和 IBinder
都会映射到 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
注释,则该类型所引用的所有其他类型也应附有该注释。在下面的示例中,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 {...}
此外,只能使用 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_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)")
会在生成的 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 生成的代码。