AIDL admite anotaciones que le brindan al compilador de AIDL información adicional sobre el elemento anotado, lo que también afecta el código auxiliar generado.
La sintaxis es similar a la de Java:
@AnnotationName(argument1=value, argument2=value) AidlEntity
Aquí, AnnotationName
es el nombre de la anotación y AidlEntity
es una entidad de AIDL como interface Foo
, void method()
o int arg
. Una anotación se adjunta a la entidad que la sigue.
Algunas anotaciones pueden tener argumentos establecidos dentro de los paréntesis, como se muestra arriba. Las anotaciones que no tienen un argumento no necesitan paréntesis. Por ejemplo:
@AnnotationName AidlEntity
Estas anotaciones no son las mismas que las anotaciones de Java, aunque se ven muy similares. Los usuarios no pueden definir anotaciones AIDL personalizadas; todas las anotaciones están predefinidas. Algunas anotaciones solo afectan a un backend determinado y no tienen efecto en otros backends. Tienen diferentes restricciones sobre dónde se pueden adjuntar.
A continuación, se incluye la lista de anotaciones de AIDL predefinidas:
Anotaciones | Se agregó en la versión de 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
declara que es posible que no se proporcione el valor de la entidad anotada.
Esta anotación solo se puede adjuntar a los tipos de datos que se devuelven de los métodos, los parámetros de los métodos y los campos parcelables.
interface IFoo {
// method return types
@nullable Data method();
// method parameters
void method2(in @nullable Data d);
}
parcelable Data {
// parcelable fields
@nullable Data d;
}
Las anotaciones no se pueden adjuntar a tipos primitivos. El siguiente es un error.
void method(in @nullable int a); // int is a primitive type
Esta anotación no tiene efecto en el backend de Java. Esto se debe a que, en Java, todos los tipos no primitivos se pasan por referencia, lo que podría ser null
.
En el backend de C++, @nullable T
se asigna a std::unique_ptr<T>
en Android 11 o versiones anteriores, y a std::optional<T>
en Android 12 o versiones posteriores.
En el backend del NDK, @nullable T
siempre se asigna a std::optional<T>
.
En el backend de Rust, @nullable T
siempre se asigna a Option<T>
.
Para un tipo similar a una lista L
, como T[]
o List<T>
, @nullable L
se asigna a std::optional<std::vector<std::optional<T>>>
(o std::unique_ptr<std::vector<std::unique_ptr<T>>>
en el caso del backend de CPP para Android 11 o versiones anteriores).
Existe una excepción a esta asignación. Cuando T
es IBinder
o una interfaz de AIDL, @nullable
no realiza ninguna operación para todos los backends, excepto para Rust. En otras palabras, tanto @nullable IBinder
como IBinder
se asignan de igual manera a android::sp<IBinder>
, que ya admite valores nulos porque es un puntero fuerte (las lecturas de CPP siguen aplicando la nulabilidad, pero el tipo sigue siendo android::sp<IBinder>
). En Rust, estos tipos son nullable
solo si se anotan con @nullable
. Se asignan a Option<T>
si se anotan.
A partir de Android 13, se puede usar @nullable(heap=true)
para los campos parcelables para modelar tipos recursivos. @nullable(heap=true)
no se puede usar con parámetros de métodos ni tipos de datos que se muestran. Cuando se anota con él, el campo se asigna a una referencia std::unique_ptr<T>
asignada al montón en los backends de C++/NDK. @nullable(heap=true)
no realiza ninguna operación en el backend de Java.
utf8InCpp
utf8InCpp
declara que un String
se representa en formato UTF8 para el backend de C++. Como su nombre lo indica, la anotación es una operación nula para otros backends.
Específicamente, String
siempre es UTF16 en el backend de Java y UTF8 en el backend del NDK.
Esta anotación se puede adjuntar en cualquier lugar donde se pueda usar el tipo String
, incluidos los valores de devolución, los parámetros, las declaraciones de constantes y los campos parcelables.
En el backend de C++, @utf8InCpp String
en AIDL se asigna a std::string
, mientras que String
sin la anotación se asigna a android::String16
, donde se usa UTF16.
Ten en cuenta que la existencia de la anotación utf8InCpp
no cambia la forma en que se transmiten las cadenas a través de la red. Las cadenas siempre se transmiten como UTF16 a través del cable. Una cadena anotada utf8InCpp
se convierte a UTF16 antes de transmitirse. Cuando se recibe una cadena, se convierte de UTF16 a UTF8 si se anotó como utf8InCpp
.
VintfStability
VintfStability
declara que se puede usar un tipo definido por el usuario (interfaz, parcelable y enum) en los dominios del sistema y del proveedor. Consulta AIDL para HALs para obtener más información sobre la interoperabilidad entre el sistema y el proveedor.
La anotación no cambia la firma del tipo, pero, cuando se establece, la instancia del tipo se marca como estable para que pueda viajar a través de los procesos del sistema y del proveedor.
La anotación solo se puede adjuntar a declaraciones de tipos definidas por el usuario, como se muestra aquí:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
Cuando un tipo se anota con VintfStability
, cualquier otro tipo al que se haga referencia en el tipo también debe anotarse como tal. En el siguiente ejemplo, Data
y IBar
deben anotarse con 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 {...}
Además, los archivos AIDL que definen tipos anotados con VintfStability
solo se pueden compilar con el tipo de módulo aidl_interface
de Soong, con la propiedad stability
establecida en "vintf"
.
aidl_interface {
name: "my_interface",
srcs: [...],
stability: &
quot;vintf",
}
UnsupportedAppUsage
La anotación UnsupportedAppUsage
indica que el tipo de AIDL anotado forma parte de la interfaz que no pertenece al SDK y a la que se puede acceder desde apps heredadas.
Consulta Restricciones en interfaces que no pertenecen al SDK para obtener más información sobre las APIs ocultas.
La anotación UnsupportedAppUsage
no afecta el comportamiento del código generado. La anotación solo anota la clase Java generada con la anotación Java del mismo nombre.
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
Esta es una operación no operativa para los backends que no son de Java.
Soporte
La anotación Backing
especifica el tipo de almacenamiento de un tipo de enumeración de AIDL.
@Backing(type="int")
enum Color { RED
, BLUE, }
En el backend de C++, esto emite una clase de enumeración de C++ del tipo int32_t
.
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
Si se omite la anotación, se supone que type
es byte
, lo que se asigna a int8_t
para el backend de C++.
El argumento type
solo se puede establecer en los siguientes tipos integrales:
byte
(8 bits de ancho)int
(32 bits de ancho)long
(64 bits de ancho)
NdkOnlyStableParcelable
NdkOnlyStableParcelable
marca una declaración (no una definición) parcelable como estable para que se pueda hacer referencia a ella desde otros tipos de AIDL estables. Es similar a JavaOnlyStableParcelable
, pero NdkOnlyStableParcelable
marca una declaración parcelable como estable para el backend del NDK en lugar de para Java.
Para usar este objeto Parcelable, haz lo siguiente:
- Debes especificar
ndk_header
. - Debes tener una biblioteca del NDK que especifique el objeto Parcelable, y la biblioteca debe compilarse en la biblioteca. Por ejemplo, en el sistema de compilación principal de un módulo
cc_*
, usastatic_libs
oshared_libs
. Paraaidl_interface
, agrega la biblioteca enadditional_shared_libraries
enAndroid.bp
.
JavaOnlyStableParcelable
JavaOnlyStableParcelable
marca una declaración (no una definición) parcelable como estable para que se pueda hacer referencia a ella desde otros tipos de AIDL estables.
El AIDL estable requiere que todos los tipos definidos por el usuario sean estables. En el caso de los objetos Parcelable, para que sean estables, sus campos deben describirse de forma explícita en el archivo fuente de 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
}
Si el objeto Parcelable no estaba estructurado (o solo se declaró), no se puede hacer referencia a él.
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable
te permite anular la verificación cuando el objeto Parcelable al que haces referencia ya está disponible de forma segura como parte del SDK de Android.
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive
genera automáticamente métodos para tipos parcelables en el backend de Java.
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
La anotación requiere parámetros adicionales para controlar lo que se generará. Los parámetros admitidos son los siguientes:
equals=true
genera los métodosequals
yhashCode
.toString=true
genera el métodotoString
que imprime el nombre del tipo y los campos. Por ejemplo:Data{number: 42, str: foo}
JavaDefault
JavaDefault
, que se agregó en Android 13, controla si se genera la compatibilidad con el control de versiones de la implementación predeterminada (para setDefaultImpl
). Esta compatibilidad ya no se genera de forma predeterminada para ahorrar espacio.
JavaPassthrough
JavaPassthrough
permite que la API de Java generada se anote con una anotación de Java arbitraria.
Las siguientes anotaciones en AIDL
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Al
ice.Value.A)")
se convierte en
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
en el código Java generado.
El valor del parámetro annotation
se emite directamente. El compilador de AIDL no analiza el valor del parámetro. Si hay algún error de sintaxis a nivel de Java, no lo detectará el compilador de AIDL, sino el compilador de Java.
Esta anotación se puede adjuntar a cualquier entidad de AIDL. Esta anotación no tiene efecto para los backends que no son de Java.
RustDerive
RustDerive
implementa automáticamente los rasgos para los tipos de Rust generados.
La anotación requiere parámetros adicionales para controlar lo que se generará. Los parámetros admitidos son los siguientes:
Copy=true
Clone=true
Ord=true
PartialOrd=true
Eq=true
PartialEq=true
Hash=true
Para obtener explicaciones sobre estos rasgos, consulta https://doc.rust-lang.org.
FixedSize
FixedSize
marca un objeto Parcelable estructurado como de tamaño fijo. Una vez marcado, el objeto parcelable no podrá tener campos nuevos agregados. Todos los campos del objeto Parcelable también deben ser tipos de tamaño fijo, incluidos los tipos primitivos, las enumeraciones, los arrays de tamaño fijo y otros objetos Parcelable marcados con FixedSize
.
Esto no proporciona ninguna garantía en diferentes cantidades de bits y no se debe confiar en él para la comunicación de cantidades de bits mixtas.
Descriptor
Descriptor
especifica de forma forzada el descriptor de interfaz de una interfaz.
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHe
llo {...}
El descriptor de esta interfaz es android.bar.IWorld
. Si falta la anotación Descriptor
, el descriptor sería android.foo.IHello
.
Esto es útil para cambiar el nombre de una interfaz ya publicada. Hacer que el descriptor de la interfaz renombrada sea el mismo que el de la interfaz antes del cambio de nombre permite que las dos interfaces se comuniquen entre sí.
@hide en comentarios
El compilador de AIDL reconoce @hide
en los comentarios y lo pasa a la salida de Java para que Metalava lo detecte. Este comentario garantiza que el sistema de compilación de Android sepa que las APIs de AIDL no son APIs del SDK.
@deprecated en comentarios
El compilador de AIDL reconoce @deprecated
en los comentarios como una etiqueta para identificar una entidad de AIDL que ya no se debe usar.
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
Cada backend marca las entidades obsoletas con una anotación o un atributo específicos del backend para que se advierta al código del cliente si hace referencia a las entidades obsoletas. Por ejemplo, la anotación @Deprecated
y la etiqueta @deprecated
se adjuntan al código generado en Java.