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>
。
如果是列表式类型 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
为空操作。换言之,@nullable IBinder
和 IBinder
都会映射到 android::sp<IBinder>
(已为 nullable,因为它是强指针)(CPP 读取仍然强制执行可为 null 性,但类型仍然是 android::sp<IBinder>
)。
从 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 后端,该注释为空操作。
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 生成的代码。