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 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, como mostrado no exemplo anterior. Anotações sem um argumento não precisam de parênteses. Exemplo:
@AnnotationName AidlEntity
Essas anotações não são as mesmas do Java, embora pareçam semelhantes. Todas as anotações são predefinidas e têm restrições quanto ao local em que podem ser anexadas. Algumas anotações afetam apenas um determinado back-end e não têm efeito em outros.
Confira a lista de anotações AIDL predefinidas:
| Anotações | Adição 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ê pode anexar essa anotação apenas a tipos de retorno de métodos, parâmetros de métodos 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;
}
Não é possível anexar anotações a tipos primitivos. O seguinte é um erro:
void method(in @nullable int a); // int is a primitive type
Essa anotação não faz nada no back-end Java. Em Java, todos os tipos não primitivos são transmitidos por referência, o que pode ser null.
No back-end do 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 do 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 do CPP para Android 11 ou versões anteriores).
Há uma exceção a esse mapeamento. Quando T é IBinder ou uma interface AIDL, @nullable não faz nada para todos os back-ends, exceto Rust. Em outras palavras, @nullable IBinder e IBinder mapeiam igualmente para android::sp<IBinder>, que já é anulável porque é um ponteiro forte. As leituras de CPP ainda impõem a capacidade de ser nulo, mas o tipo ainda é android::sp<IBinder>. Em Rust, esses tipos são nullable somente 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 e 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 std::unique_ptr<T> alocada por heap nos back-ends
do CPP e do NDK. @nullable(heap=true) não faz nada 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 é uma operação nula para outros back-ends.
Especificamente, String é sempre UTF16 no back-end Java e UTF8 no back-end do NDK.
Essa anotação pode ser anexada em qualquer lugar em que o tipo String possa ser usado, incluindo valores de retorno, parâmetros, declarações de constantes e campos parceláveis.
Para o back-end CPP, @utf8InCpp String em AIDL é mapeado para std::string, em que
String sem a anotação é mapeado para android::String16 quando UTF16 é usado.
VintfStability
VintfStability declara que um tipo definido pelo usuário (interface, parcelable e enum) pode ser usado em todos os domínios do sistema e do fornecedor. Consulte
AIDL para HALs para saber mais sobre
interoperabilidade entre fornecedores e sistemas.
A anotação não muda a assinatura do tipo, mas, quando ela é definida, a instância do tipo é marcada como estável para que possa transitar entre os 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 estava acessível para apps legados.
Consulte Restrições para interfaces que não sã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 de mesmo nome:
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
Essa é uma operação nula para back-ends que não são Java.
Anotação de apoio
A anotação Backing especifica o tipo de armazenamento de um tipo de enumeração AIDL:
@Backing(type="int")
enum Color { RED, BLUE, }
No back-end CPP, isso emite uma classe de enumeração 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 no back-end do CPP.
O argumento type só pode ser definido como os seguintes tipos integrais:
byte(8 bits de largura)int(32 bits de largura)long(64 bits)
NdkOnlyStableParcelable
NdkOnlyStableParcelable marca uma declaração (não definição) parcelável
como estável para que possa ser referenciada de outros tipos AIDL estáveis. Isso é como JavaOnlyStableParcelable, mas NdkOnlyStableParcelable marca uma declaração parcelable como estável para o back-end do NDK em vez de para Java.
Para usar esse parcelable:
- É necessário especificar
ndk_header. - Você precisa ter uma biblioteca do NDK especificando o parcelable, e ela 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 (não definição) parcelável
como estável para que possa ser referenciada de outros tipos AIDL estáveis.
A AIDL estável exige que todos os tipos definidos pelo usuário sejam estáveis. Para parcelables, ser estável exige que os campos sejam descritos explicitamente no arquivo de origem 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 parcelable não for estruturado (ou apenas declarado), não será possível fazer referência a ele:
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable permite substituir a verificação quando o parcelable
a que você está fazendo referência está disponível com segurança como parte do SDK do Android:
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
O 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 mais parâmetros para controlar o que gerar. Os parâmetros aceitos são:
- O
equals=truegera métodosequalsehashCode. - O
toString=truegera o métodotoString, que imprime o nome do tipo e os campos, por exemplo,Data{number: 42, str: foo}.
JavaDefault (descontinuado)
O JavaDefault, adicionado no Android 13, controla se o suporte ao controle de versões da implementação padrão é gerado (para setDefaultImpl). Esse suporte não é mais gerado por padrão para economizar espaço.
JavaPassthrough
O JavaPassthrough permite que a API Java gerada seja anotada com uma anotação
Java arbitrária.
Estas anotações em AIDL:
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")
serão transformados no seguinte 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 AIDL
não examina o valor do parâmetro. Se houver um erro de sintaxe no nível do Java, ele não será detectado pelo compilador AIDL, mas pelo compilador Java.
Essa anotação pode ser anexada a qualquer entidade AIDL. Essa anotação é uma operação nula para back-ends que não são Java.
RustDerive
O RustDerive implementa automaticamente características para tipos Rust gerados.
A anotação exige mais parâmetros 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 (em inglês).
FixedSize
FixedSize marca um parcelable estruturado como de tamanho fixo. Depois que ele é marcado, não é possível adicionar novos campos ao parcelable. Todos os campos do
parcelable precisam ser tipos de tamanho fixo, incluindo tipos primitivos,
enums, matrizes de tamanho fixo e outros parcelables marcados com FixedSize.
Descritor
Descriptor especifica à força o descritor de interface de uma interface:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
O descritor desta 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 fazer com que o descritor da interface renomeada seja igual ao descritor da interface antes da renomeação, as duas interfaces podem se comunicar.
@hide nos comentários
O compilador AIDL reconhece @hide em 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 AIDL não são APIs do SDK.
@deprecated em comentários
O compilador AIDL reconhece @deprecated em comentários como uma tag para identificar uma
entidade 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 se referir às
entidades descontinuadas. Por exemplo, a anotação @Deprecated e a tag @deprecated
são anexadas ao código gerado em Java.