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 acima. Anotações sem um argumento não precisam de parênteses. Exemplo:
@AnnotationName AidlEntity
Essas anotações não são as mesmas que as anotações do Java, embora sejam muito parecidas. Os usuários não podem definir anotações AIDL personalizadas. Todas as anotações são predefinidas. Algumas anotações afetam apenas um determinado back-end e não fazem nada em outros. Elas têm restrições diferentes sobre onde podem ser anexadas.
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 não pode ser fornecido.
Essa anotação só pode ser anexada 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. Isso ocorre porque, 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
sempre é mapeado para std::optional<T>
.
No back-end do Rust, @nullable T
sempre é 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 aplicam a nulidade, 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 CPP/NDK. @nullable(heap=true)
não faz nada no back-end Java.
utf8InCpp
utf8InCpp
declara que um 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 do CPP, @utf8InCpp String
na AIDL é mapeado para std::string
, enquanto
String
sem a anotação é mapeado para android::String16
, em que UTF16 é usado.
A existência da anotação utf8InCpp
não muda a forma como as strings são transmitidas pela rede. As strings são sempre transmitidas como UTF16
pelo cabo. Uma string anotada utf8InCpp
é convertida para UTF16 antes de ser
transmitida. Quando uma string é recebida, ela é convertida de UTF16 para UTF8 se tiver sido
anotada como utf8InCpp
.
VintfStability
VintfStability
declara que um tipo definido pelo usuário (interface, parcelable e enumeração) 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
devem 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: &
quot;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 só anota 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.
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, o type
será considerado byte
, que mapeia 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 de largura)
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_libs
oushared_libs
. Paraaidl_interface
, adicione a biblioteca emadditional_shared_libraries
noAndroid.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), 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 parcelable
a que você está fazendo referência já 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=true
gera métodosequals
ehashCode
. - O
toString=true
gera o métodotoString
, que imprime o nome do tipo e os campos. Por exemplo:Data{number: 42, str: foo}
JavaDefault
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.
As seguintes anotações em AIDL
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Al
ice.Value.A)")
se tornar
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
no código Java gerado.
O valor do parâmetro annotation
é emitido diretamente. O compilador AIDL
não analisa 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=true
Clone=true
Ord=true
PartialOrd=true
Eq=true
PartialEq=true
Hash=true
Para explicações sobre essas características, consulte https://doc.rust-lang.org.
FixedSize
FixedSize
marca um parcelable estruturado como de tamanho fixo. Depois de marcada, a
parcelable não poderá ter novos campos adicionados. Todos os campos do
parcelable também precisam ser tipos de tamanho fixo, incluindo tipos primitivos,
enums, matrizes de tamanho fixo e outros parcelables marcados com FixedSize
.
Isso não oferece nenhuma garantia em diferentes tamanhos de bits e não deve ser usado para comunicação de tamanho de bits misto.
Descritor
Descriptor
especifica à força o descritor de interface de uma interface.
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHe
llo {...}
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 garante que o sistema de build do Android saiba 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.