Anotações em AIDL

AIDL suporta anotações que fornecem ao compilador 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 que não têm um argumento não precisam de parênteses. Por exemplo:

@AnnotationName AidlEntity

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

Abaixo está a lista de anotações AIDL pré-definidas:

Anotações Adicionado na versão Android
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
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.

Esta 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;
}

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

Esta anotação não é operacional para o back-end Java. Isso ocorre porque, em Java, todos os tipos não primitivos são passados ​​por referência, que pode ser null .

No back-end CPP, @nullable T mapeia para std::unique_ptr<T> no Android 11 ou inferior e para std::optional<T> no Android 12 ou superior.

No back-end do NDK, @nullable T sempre mapeia para std::optional<T> .

Para um tipo de lista L , como T[] ou List<T> , @nullable L mapeia 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 Android 11 ou inferior).

Há uma exceção a esse mapeamento. Quando T é IBinder ou uma interface AIDL, @nullable é no-op. Em outras palavras, @nullable IBinder e IBinder igualmente mapeiam para android::sp<IBinder> , que já é anulável porque é um ponteiro forte (leituras CPP ainda impõem a nulidade, mas o tipo ainda é android::sp<IBinder> ).

Começando com o Android T (AOSP experimental), @nullable(heap=true) pode ser usado para campos parcelables 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/NDK. @nullable(heap=true) não é operacional no back-end Java.

utf8InCpp

utf8InCpp declara que uma String é representada no formato UTF8 para o back-end CPP. Como o próprio nome indica, a anotação não é operacional para outros back-ends. Especificamente, String é sempre UTF16 no backend Java e UTF8 no backend NDK.

Esta anotação pode ser anexada em qualquer lugar onde o tipo String possa ser usado, incluindo valores de retorno, parâmetros, declarações constantes e campos parcelable.

Para o back-end CPP, @utf8InCpp String em AIDL mapeia para std::string , enquanto String sem a anotação mapeia para android::String16 onde UTF16 é usado.

Observe que a existência da anotação utf8InCpp não altera a maneira como as strings são transmitidas pelo fio. Strings são sempre transmitidas como UTF16 pelo fio. Uma string anotada utf8InCpp é convertida em UTF16 antes de ser transmitida. Quando uma string é recebida, ela é convertida de UTF16 para UTF8 se tiver sido anotada como utf8InCpp .

Estabilidade Vintf

VintfStability declara que um tipo definido pelo usuário (interface, parcelable e enum) pode ser usado nos domínios do sistema e do fornecedor. Consulte AIDL para HALs para obter mais informações sobre a interoperabilidade do sistema com o fornecedor.

A anotação não altera a assinatura do tipo, mas quando é definida, a instância do tipo é marcada como estável para que possa percorrer 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 abaixo:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Quando um tipo é anotado com VintfStability , qualquer outro tipo referenciado no tipo também deve ser anotado como tal. No exemplo abaixo, 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 os tipos anotados com VintfStability só podem ser construídos usando o tipo de módulo aidl_interface Soong, com a propriedade de stability definida como "vintf" .

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

Uso de aplicativo não suportado

A anotação UnsupportedAppUsage indica que o tipo AIDL anotado faz parte da interface não SDK que pode ser acessada por aplicativos herdados. Consulte Restrições em interfaces não SDK para obter mais informações sobre as APIs ocultas.

A anotação UnsupportedAppUsage não afeta o comportamento do código gerado. A anotação apenas 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 {...}

Este é um não-op para back-ends não Java.

Apoio

A anotação de Backing especifica o tipo de armazenamento de um tipo de enumeração AIDL.

@Backing(type="int")
enum Color { RED, BLUE, }

No back-end CPP, o código acima 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 CPP.

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

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

JavaOnlyStableParcelable

JavaOnlyStableParcelable marca uma declaração parcelable (não definição) como estável para que possa ser referenciada de outros tipos AIDL estáveis.

O AIDL estável requer que todos os tipos definidos pelo usuário sejam estáveis. Para parcelables, ser estável requer que seus campos sejam explicitamente descritos 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 apenas declarado), ele não pode ser referenciado.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable permite substituir a verificação quando o parcelable que você está referenciando já está disponível com segurança como parte do Android SDK.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive gera automaticamente métodos para tipos parcelable no backend 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 suportados são:

  • equals=true gera métodos equals e hashCode .
  • toString=true gera o método toString que imprime o nome do tipo e dos campos. Por exemplo: Data{number: 42, str: foo}

JavaDefault

JavaDefault , adicionado no Android T (AOSP experimental), controla se o suporte de versão de implementação padrão é gerado (para setDefaultImpl ). Este 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 em AIDL

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

vir a ser

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

no código Java gerado.

O valor do parâmetro de annotation é emitido diretamente. O compilador AIDL não analisa o valor do parâmetro. Se houver algum erro de sintaxe no nível do Java, ele não será detectado pelo compilador AIDL, mas pelo compilador Java.

Esta anotação pode ser anexada a qualquer entidade AIDL. Esta anotação não é operacional para back-ends não Java.

Tamanho fixo

FixedSize marca um parcelal estruturado como tamanho fixo. Uma vez marcado, o parcelable não poderá ter novos campos adicionados a ele. Todos os campos do parcelable também devem ser tipos de tamanho fixo, incluindo tipos primitivos, enums, arrays de tamanho fixo e outros parcelables marcados com FixedSize .

Isso não oferece nenhuma garantia em diferentes bits e não deve ser usado para comunicação de bits mistos.

Descritor

Descriptor especifica forçosamente o descritor de interface de uma interface.

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

O descritor da interface acima é android.bar.IWorld . Se a anotação do Descriptor estiver ausente, o descritor será android.foo.IHello .

Isso é útil para renomear uma interface já publicada. Tornar o descritor da interface renomeada igual ao descritor da interface antes da renomeação permite que as duas interfaces se comuniquem.

@esconder nos comentários

O compilador AIDL reconhece @hide nos comentários e o passa para a saída Java para o metalava coletar. Este comentário garante que o sistema de compilação do Android saiba que as APIs AIDL não são APIs do SDK.

@obsoleto 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 obsoletas com uma anotação/atributo específico de back-end para que o código do cliente seja avisado se ele se referir às entidades obsoletas. Por exemplo, a anotação @Deprecated e a tag @deprecated são anexadas ao código gerado em Java.