Anotações na AIDL

O AIDL oferece suporte a anotações que fornecem 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. As anotações que não têm um argumento não precisam de parênteses. Exemplo:

@AnnotationName AidlEntity

Essas anotações não são iguais às anotações do Java, embora pareçam muito semelhantes. Os usuários não podem definir anotações AIDL personalizadas. Elas são todas predefinidas. Algumas anotações afetam apenas um determinado back-end e não têm efeito em outros. Eles têm diferentes restrições de onde podem ser anexados.

Confira a lista de anotações predefinidas de AIDL:

Anotações Adicionado à 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

anulável

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étodo, parâmetros de método e campos parcelable.

interface IFoo {
    // method return types
    @nullable Data method();

    // method parameters
    void method2(in @nullable Data d);
}

parcelable Data {
    // parcelable fields
    @nullable Data d;
}

Anotações não podem ser anexadas a tipos primitivos. O exemplo a seguir é um erro.

void method(in @nullable int a); // int is a primitive type

Essa anotação é uma operação nula para o back-end Java. Isso ocorre porque, em Java, todos os tipos não primitivos são transmitidos por referência, que pode ser null.

No back-end do CPP, @nullable T é associado a std::unique_ptr<T> no Android 11 ou versões anteriores e a std::optional<T> no Android 12 ou mais recente.

No back-end do NDK, @nullable T sempre é associado a std::optional<T>.

No back-end Rust, @nullable T sempre é associado a Option<T>.

Para um tipo L semelhante a lista, como T[] ou List<T>, @nullable L é associado a 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 é autônomo para todos os back-ends, exceto para o Rust. Em outras palavras, @nullable IBinder e IBinder são mapeados igualmente para android::sp<IBinder>, que já é anulável porque é um indicador forte. As leituras de CPP ainda impõem a anulabilidade, mas o tipo ainda é android::sp<IBinder>. Em Rust, esses tipos são nullable somente se anotados com @nullable. Eles são mapeados para Option<T> se forem anotados.

A partir do Android 13, o @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, o campo é mapeado para uma referência std::unique_ptr<T> alocada na pilha nos back-ends CPP/NDK. @nullable(heap=true) é uma operação nula 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 maneira como as strings são transmitidas pela rede. As strings são sempre transmitidas como UTF16 pela rede. Uma string com anotação 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 enum) pode ser usado em todos os domínios do sistema e do 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 ser transmitida 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 que seja referenciado no tipo também precisa ser anotado dessa forma. No exemplo abaixo, 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 Soong aidl_interface, com a propriedade stability definida como "vintf".

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

UnsupportedAppUsage

A anotação UnsupportedAppUsage indica que o tipo de AIDL anotado faz parte da interface não SDK que foi 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 com o mesmo nome.

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

Isso não é uma operação 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 do 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 é mapeado para int8_t para o back-end do CPP.

O argumento type só pode ser definido para os seguintes tipos integrais:

  • byte (largura de 8 bits)
  • int (largura de 32 bits)
  • long (largura de 64 bits)

NdkOnlyStableParcelable

NdkOnlyStableParcelable marca uma declaração parcelável (não a definição) como estável para que ela possa ser referenciada em outros tipos de AIDL estáveis. Isso é semelhante a JavaOnlyStableParcelable, mas NdkOnlyStableParcelable marca uma declaração parcelável como estável para o back-end do NDK em vez do Java.

Para usar esse parcelable:

  • É necessário especificar ndk_header.
  • É necessário ter uma biblioteca do NDK que especifique o parcelável, e ela precisa ser compilada na biblioteca. Por exemplo, no sistema de build principal em um módulo cc_*, use static_libs ou shared_libs. Para aidl_interface, adicione a biblioteca em additional_shared_libraries em Android.bp.

JavaOnlyStableParcelable

JavaOnlyStableParcelable marca uma declaração parcelável (não a definição) como estável para que ela possa ser referenciada em 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 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 foi estruturado (ou acabou de ser declarado), ele não poderá ser referenciado.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable permite que você substitua a verificação quando o parcelable que você está referenciando 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 requer parâmetros adicionais para controlar o que gerar. Os parâmetros aceitos são:

  • equals=true gera os métodos equals e hashCode.
  • toString=true gera um método toString que mostra 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 de versionamento 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.

As seguintes anotações na AIDL

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.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 verifica o valor do parâmetro. Se houver algum erro de sintaxe no nível do Java, ele não será capturado 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.

FixedSize

FixedSize marca um elemento parcelável estruturado como de tamanho fixo. Depois de marcado, o parcelável não poderá ter novos campos adicionados a ele. Todos os campos do parcelável também precisam ser de tamanho fixo, incluindo tipos primitivos, enums, matrizes de tamanho fixo e outros parceláveis marcados com FixedSize.

Isso não oferece garantia em diferentes bitnesses e não deve ser usado para comunicação com bitness misto.

Descritor

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. Fazer com que o descritor da interface renomeada seja o mesmo que o descritor da interface antes da renomeação permite que as duas interfaces se comuniquem.

@hide in comments

O compilador AIDL reconhece @hide em comentários e o transmite para a saída Java para que o metalava possa ser usado. Esse comentário garante que o sistema de build do Android saiba que as APIs AIDL não são APIs do SDK.

@deprecated nos comentários

O compilador AIDL reconhece @deprecated nos 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 um atributo específico do back-end para que o código do cliente seja avisado se ele se referir às entidades descontinuadas. Por exemplo, a anotação @Deprecated e a tag @deprecated são anexadas ao código gerado em Java.