AIDL supports annotations that give the AIDL compiler extra info about the annotated element, which also affects the generated stub code.
The syntax is similar to that of Java:
@AnnotationName(argument1=value, argument2=value) AidlEntity
Here, AnnotationName is the name of the annotation, and AidlEntity is
an AIDL entity like interface Foo, void method(), or int arg. An
annotation is attached to the entity that follows it.
Some annotations can have arguments set inside the parentheses, as shown in the previous example. Annotations that don't have an argument don't need the parentheses. For example:
@AnnotationName AidlEntity
These annotations aren't the same as the Java annotations, although they look similar. All annotations are all predefined, and have restrictions for where you can attach them. Some annotations affect only a certain backend and are no-op in other backends.
Here is the list of predefined AIDL annotations:
| Annotations | Added in Android version |
|---|---|
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 declares that the value of the annotated entity can be null.
You can attach this annotation only to method return types, method parameters, and parcelable fields:
interface IFoo {
// method return types
@nullable Data method();
// method parameters
void method2(in @nullable Data d);
}
parcelable Data {
// parcelable fields
@nullable Data d;
}
Annotations can't be attached to primitive types. The following is an error:
void method(in @nullable int a); // int is a primitive type
This annotation is no-op for the Java backend. In Java, all
nonprimitive types are passed by reference, which could be null.
In the CPP backend, @nullable T maps to std::unique_ptr<T> in Android
11 or lower, and to std::optional<T> in Android 12 or higher.
In the NDK backend, @nullable T maps to std::optional<T>.
In the Rust backend, @nullable T maps to Option<T>.
For a list-like type L such as T[] or List<T>, @nullable L maps to
std::optional<std::vector<std::optional<T>>> (or
std::unique_ptr<std::vector<std::unique_ptr<T>>> in case of the CPP backend
for Android 11 or lower).
There is an exception to this mapping. When T
is IBinder or an AIDL interface, @nullable is no-op for all backends except
for Rust. In other words, both
@nullable IBinder and IBinder equally map to android::sp<IBinder>, which
is already nullable because it is a strong pointer (CPP reads still
enforce nullability, but the type is still android::sp<IBinder>). In Rust,
these types are nullable only if annotated with @nullable. They map to
Option<T> if annotated.
Beginning with Android 13, @nullable(heap=true) can be used for
parcelable fields to model recursive types. @nullable(heap=true) can't be used
with method parameters or return types. When annotated with it, the field is
mapped to a heap-allocated reference std::unique_ptr<T> in the CPP and NDK
backends. @nullable(heap=true) is no-op in the Java backend.
utf8InCpp
utf8InCpp declares that String is represented in UTF8 format for the CPP
backend. As its name indicates, the annotation is a no-op for other backends.
Specifically, String is always UTF16 in the Java backend and UTF8 in the NDK
backend.
This annotation can be attached anywhere the String type can be used,
including return values, parameters, constant declarations, and parcelable
fields.
For the CPP backend, @utf8InCpp String in AIDL maps to std::string, where
String without the annotation maps to android::String16 where UTF16 is used.
VintfStability
VintfStability declares that a user-defined type (interface, parcelable,
and enum) can be used across the system and vendor domains. See
AIDL for HALs for more about
system-vendor interoperability.
The annotation doesn't change the signature of the type, but when it's set, the instance of the type is marked as stable so that it can travel across the vendor and system processes.
The annotation can be attached only to user-defined type declarations as shown here:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
When a type is annotated with VintfStability, any other type that is
referenced in the type should also be annotated as such. In the following
example, Data and IBar should both be annotated with 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 {...}
In addition, the AIDL files defining types annotated with VintfStability
can only be built using the aidl_interface Soong module type, with the
stability property set to vintf:
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
The UnsupportedAppUsage annotation denotes that the annotated AIDL type is
part of the non-SDK interface that has been accessible for legacy apps.
See Restrictions on non-SDK
interfaces
for more information about the hidden APIs.
The UnsupportedAppUsage annotation doesn't affect the behavior of the
generated code. The annotation annotates only the generated Java class with the
Java annotation of the same name:
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
This is a no-op for non-Java backends.
Backing annotation
The Backing annotation specifies the storage type of an AIDL enum type:
@Backing(type="int")
enum Color { RED, BLUE, }
In the CPP backend, this emits a C++ enum class of type int32_t:
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
If the annotation is omitted, type is assumed to be byte, which maps
to int8_t for the CPP backend.
The type argument can be set only to the following integral types:
byte(8-bit wide)int(32-bit wide)long(64-bit wide)
NdkOnlyStableParcelable
NdkOnlyStableParcelable marks a parcelable declaration (not definition)
as stable so that it can be referenced from other stable AIDL types. This
is like JavaOnlyStableParcelable, but
NdkOnlyStableParcelable marks a parcelable declaration as stable for the NDK
backend instead of for Java.
To use this parcelable:
- You must specify
ndk_header. - You must have an NDK library specifying the parcelable and the library must
be compiled into the library. For example, in the core build system on a
cc_*module, usestatic_libsorshared_libs. Foraidl_interface, add the library underadditional_shared_librariesinAndroid.bp.
JavaOnlyStableParcelable
JavaOnlyStableParcelable marks a parcelable declaration (not definition)
as stable so that it can be referenced from other stable AIDL types.
Stable AIDL requires that all user-defined types are stable. For parcelables, being stable requires that its fields are explicitly described in the AIDL source file:
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
}
If the parcelable is unstructured (or just declared), then it can't be referenced:
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable lets you override the check when the parcelable
you're referencing is safely available as part of the Android SDK:
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive automatically generates methods for parcelable types in the
Java backend:
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
The annotation requires additional parameters to control what to generate. The supported parameters are:
equals=truegeneratesequalsandhashCodemethods.toString=truegeneratestoStringmethod that prints the name of the type and fields, for example,Data{number: 42, str: foo}.
JavaDefault (deprecated)
JavaDefault, added in Android 13, controls whether
the default implementation versioning support is generated (for
setDefaultImpl). This support is no longer generated by default in order to
save space.
JavaPassthrough
JavaPassthrough lets the generated Java API be annotated with an arbitrary
Java annotation.
These annotations in AIDL:
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")
become the following in the generated Java code:
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
The value of the annotation parameter is directly emitted. The AIDL
compiler doesn't examine the value of the parameter. If there's any
Java-level syntax error, it won't be caught by the AIDL compiler but by the
Java compiler.
This annotation can be attached to any AIDL entity. This annotation is a no-op for non-Java backends.
RustDerive
RustDerive automatically implements traits for generated Rust types.
The annotation requires additional parameters to control what to generate. The supported parameters are:
Copy=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
For explanations of these traits, see Rust Documentation.
FixedSize
FixedSize marks a structured parcelable as fixed size. After it's marked, you
can't add new fields to the parcelable. All fields of
the parcelable must be fixed sized types, including primitive types,
enums, fixed-size arrays, and other parcelables marked with FixedSize.
Descriptor
Descriptor forcibly specifies the interface descriptor of an interface:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
The descriptor of this interface is android.bar.IWorld. If the
Descriptor annotation is missing, the descriptor would be
android.foo.IHello.
This is useful for renaming an already published interface. Making the descriptor of the renamed interface the same as the descriptor of the interface before the renaming allows the two interfaces to talk to each other.
@hide in comments
The AIDL compiler recognizes @hide in comments and passes it through
to Java output for metalava to pickup. This comment helps ensure that the
Android build system recognizes that AIDL APIs aren't SDK APIs.
@deprecated in comments
The AIDL compiler recognizes @deprecated in comments as a tag to identify an
AIDL entity that should no longer be used:
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
Each backend marks deprecated entities with a backend-specific annotation or
attribute so that the client code is warned if it refers the deprecated
entities. For example, the @Deprecated annotation and the @deprecated
tag are attached to the Java generated code.