A AIDL oferece suporte a anotações que fornecem ao compilador da AIDL informações extras sobre o elemento anotado, o que também afeta o código stub gerado.
A sintaxe é semelhante à do Java:
@AnnotationName(argument1=value, argument2=value) AidlEntity
Aqui, AnnotationName é o nome da anotação e AidlEntity é uma entidade da AIDL, como interface Foo, void method() ou int arg. Uma anotação é anexada à entidade que a segue.
Algumas anotações podem ter argumentos definidos entre parênteses, conforme mostrado no exemplo anterior. As anotações que não têm um argumento não precisam dos parênteses. Exemplo:
@AnnotationName AidlEntity
Essas anotações não são as mesmas que as anotações Java, embora pareçam semelhantes. Todas as anotações são predefinidas e têm restrições sobre onde podem ser anexadas. Algumas anotações afetam apenas um back-end específico e não têm efeito em outros back-ends.
Confira a lista de anotações predefinidas da AIDL:
| Anotações | Adicionadas na versão do 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 o valor da entidade anotada pode ser nulo.
Você só pode anexar essa anotação a tipos de retorno de método, parâmetros de método e campos parceláveis:
interface IFoo {
// method return types
@nullable Data method();
// method parameters
void method2(in @nullable Data d);
}
parcelable Data {
// parcelable fields
@nullable Data d;
}
As anotações não podem ser anexadas a tipos primitivos. O seguinte é um erro:
void method(in @nullable int a); // int is a primitive type
Essa anotação não tem efeito no back-end Java. Em Java, todos os tipos não primitivos são transmitidos por referência, que pode ser null.
No back-end CPP, @nullable T é mapeado para std::unique_ptr<T> no Android
11 ou versões anteriores e para std::optional<T> no Android 12 ou versões mais recentes.
No back-end NDK, @nullable T é mapeado para std::optional<T>.
No back-end Rust, @nullable T é mapeado para Option<T>.
Para um tipo semelhante a uma lista L como T[] ou List<T>, @nullable L é mapeado para
std::optional<std::vector<std::optional<T>>> (ou
std::unique_ptr<std::vector<std::unique_ptr<T>>> no caso do back-end CPP
para o Android 11 ou versões anteriores).
Há uma exceção a esse mapeamento. Quando T é IBinder ou uma interface da AIDL, @nullable não tem efeito para todos os back-ends, exceto o Rust. Em outras palavras, tanto
@nullable IBinder quanto IBinder são mapeados igualmente para android::sp<IBinder>, que
já é anulável porque é um ponteiro forte (as leituras CPP ainda
aplicam a anulabilidade, mas o tipo ainda é android::sp<IBinder>). No Rust,
esses tipos são nullable apenas se forem anotados com @nullable. Eles são mapeados para
Option<T> se forem anotados.
A partir do Android 13, @nullable(heap=true) pode ser usado para campos parceláveis para modelar tipos recursivos. @nullable(heap=true) não pode ser usado com parâmetros de método ou tipos de retorno. Quando anotado com ele, o campo é
mapeado para uma referência alocada por heap std::unique_ptr<T> nos back-ends CPP e NDK. @nullable(heap=true) não tem efeito no back-end Java.
utf8InCpp
utf8InCpp declara que String é representado no formato UTF8 para o back-end CPP. Como o nome indica, a anotação não tem efeito para outros back-ends.
Especificamente, String é sempre UTF16 no back-end Java e UTF8 no back-end NDK.
Essa anotação pode ser anexada a qualquer lugar em que o tipo String possa ser usado, incluindo valores de retorno, parâmetros, declarações constantes e campos parceláveis.
Para o back-end CPP, @utf8InCpp String na AIDL é mapeado para std::string, onde
String sem a anotação é mapeado para android::String16, em que UTF16 é usado.
VintfStability
VintfStability declara que um tipo definido pelo usuário (interface, parcelável e enum) pode ser usado em domínios de sistema e fornecedor. Consulte
AIDL para HALs para saber mais sobre a
interoperabilidade entre o sistema e o fornecedor.
A anotação não muda a assinatura do tipo, mas, quando definida, a instância do tipo é marcada como estável para que possa viajar pelos processos do fornecedor e do sistema.
A anotação só pode ser anexada a declarações de tipo definidas pelo usuário, conforme mostrado aqui:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
Quando um tipo é anotado com VintfStability, qualquer outro tipo referenciado nele também precisa ser anotado como tal. No exemplo a seguir, Data e IBar precisam ser anotados com 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 {...}
Além disso, os arquivos AIDL que definem tipos anotados com VintfStability só podem ser criados usando o tipo de módulo aidl_interface do Soong, com a propriedade stability definida como vintf:
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
A anotação UnsupportedAppUsage indica que o tipo AIDL anotado faz parte da interface não SDK que está acessível para apps legados.
Consulte Restrições para interfaces não SDK
para mais informações sobre as APIs ocultas.
A anotação UnsupportedAppUsage não afeta o comportamento do código gerado. A anotação anota apenas a classe Java gerada com a anotação Java do mesmo nome:
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
Essa anotação não tem efeito para back-ends não Java.
Anotação de back-end
A anotação Backing especifica o tipo de armazenamento de um tipo de enum da AIDL:
@Backing(type="int")
enum Color { RED, BLUE, }
No back-end CPP, isso emite uma classe de enum C++ do tipo int32_t:
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
Se a anotação for omitida, type será considerado byte, que é mapeado para int8_t para o back-end CPP.
O argumento type só pode ser definido para os seguintes tipos integrais:
byte(8 bits de largura)int(32 bits de largura)long(64 bits de largura)
NdkOnlyStableParcelable
NdkOnlyStableParcelable marca uma declaração parcelável (não uma definição) como estável para que ela possa ser referenciada por outros tipos de AIDL estáveis. Isto
é semelhante a JavaOnlyStableParcelable, mas
NdkOnlyStableParcelable marca uma declaração parcelável como estável para o back-end NDK
em vez de Java.
Para usar esse parcelável:
- É necessário especificar
ndk_header. - Você precisa ter uma biblioteca NDK especificando o parcelável, e a biblioteca precisa ser compilada na biblioteca. Por exemplo, no sistema de build principal em um módulo
cc_*, usestatic_libsoushared_libs. Paraaidl_interface, adicione a biblioteca emadditional_shared_librariesnoAndroid.bp.
JavaOnlyStableParcelable
JavaOnlyStableParcelable marca uma declaração parcelável (não uma definição) como estável para que ela possa ser referenciada por outros tipos de AIDL estáveis.
A AIDL estável exige que todos os tipos definidos pelo usuário sejam estáveis. Para parceláveis, ser estável exige que os campos sejam descritos explicitamente no arquivo de origem da 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
}
Se o parcelável não for estruturado (ou apenas declarado), ele não poderá ser referenciado:
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable permite substituir a verificação quando o parcelável referenciado está disponível com segurança como parte do SDK do Android:
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive gera automaticamente métodos para tipos parceláveis no back-end Java:
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
A anotação exige parâmetros adicionais para controlar o que gerar. Os parâmetros aceitos são:
equals=truegera métodosequalsehashCode.toString=truegera o métodotoStringque imprime o nome do tipo e dos campos, por exemplo,Data{number: 42, str: foo}.
JavaDefault (descontinuado)
JavaDefault, adicionada no Android 13, controla se o suporte ao controle de versões de implementação padrão é gerado (para setDefaultImpl). Esse suporte não é mais gerado por padrão para economizar espaço.
JavaPassthrough
JavaPassthrough permite que a API Java gerada seja anotada com uma anotação Java arbitrária.
Essas anotações na AIDL:
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")
se tornam o seguinte no código Java gerado:
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
O valor do parâmetro annotation é emitido diretamente. O compilador da AIDL não examina o valor do parâmetro. Se houver algum erro de sintaxe no nível do Java, ele não será detectado pelo compilador da AIDL, mas pelo compilador Java.
Essa anotação pode ser anexada a qualquer entidade da AIDL. Essa anotação não tem efeito para back-ends não Java.
RustDerive
RustDerive implementa automaticamente características para tipos Rust gerados.
A anotação exige parâmetros adicionais para controlar o que gerar. Os parâmetros aceitos são:
Copy=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
Para explicações sobre essas características, consulte a documentação do Rust.
FixedSize
FixedSize marca um parcelável estruturado como de tamanho fixo. Depois de marcado, não é possível adicionar novos campos ao parcelável. Todos os campos do parcelável precisam ser tipos de tamanho fixo, incluindo tipos primitivos, enums, matrizes de tamanho fixo e outros parceláveis marcados com FixedSize.
Os objetos FixedSize têm tamanhos e alinhamentos estáveis no back-end ndk.
| Tipo | Tamanho (bytes) | Alinhamento (bytes) |
|---|---|---|
boolean |
1 |
1 |
byte |
1 |
1 |
char |
2 |
2 |
int |
4 |
4 |
long |
8 |
8 |
float |
4 |
4 |
double |
8 |
8 |
parcelable |
Tamanho total de todos os campos | Maior alinhamento de todos os campos |
union |
Maior tamanho de todos os campos | Maior alinhamento de todos os campos |
enum |
Tamanho do tipo de back-end | Alinhamento do tipo de back-end |
T[N] (matriz de tamanho fixo) |
Tamanho de T * N |
Alinhamento de T |
String, IBinder, FileDescriptor, ParcelFileDescriptor |
N/A |
N/A |
Descriptor
Descriptor especifica à força o descritor de interface de uma interface:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
O descritor dessa interface é android.bar.IWorld. Se a anotação Descriptor estiver ausente, o descritor será android.foo.IHello.
Isso é útil para renomear uma interface já publicada. Ao tornar o descritor da interface renomeada igual ao descritor da interface antes da renomeação, as duas interfaces podem se comunicar.
@hide em comentários
O compilador da AIDL reconhece @hide nos comentários e o transmite para a saída Java para que o Metalava o colete. Esse comentário ajuda a garantir que o sistema de build do Android reconheça que as APIs da AIDL não são APIs do SDK.
@deprecated em comentários
O compilador da AIDL reconhece @deprecated nos comentários como uma tag para identificar uma entidade da AIDL que não deve mais ser usada:
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
Cada back-end marca entidades descontinuadas com uma anotação ou atributo específico do back-end para que o código do cliente seja avisado se referir às entidades descontinuadas. Por exemplo, a anotação @Deprecated e a tag @deprecated são anexadas ao código Java gerado.