Anotações em AIDL

AIDL oferece suporte a 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 colocados entre parênteses, conforme mostrado acima. Anotações que não possuem argumento não precisam de parênteses. Por exemplo:

@AnnotationName AidlEntity

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

Abaixo está a lista de anotações AIDL predefinidas:

Anotações Adicionado na versão 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.

Esta anotação só pode ser anexada a tipos de retorno de método, parâmetros de método e campos parcelados.

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 funciona para o back-end Java. Isso porque, em Java, todos os tipos não primitivos são passados ​​por referência, que poderia ser null .

No back-end do 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 L semelhante a uma lista, 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 é autônomo. Em outras palavras, @nullable IBinder e IBinder mapeiam igualmente para android::sp<IBinder> , que já é anulável porque é um ponteiro forte (as leituras do CPP ainda impõem nulidade, mas o tipo ainda é android::sp<IBinder> ).

A partir do Android 13, @nullable(heap=true) pode ser usado para campos parcelados 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 em heap std::unique_ptr<T> nos back-ends CPP/NDK. @nullable(heap=true) não funciona no back-end Java.

utf8InCpp

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

Essa 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 parcelados.

Para o backend 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 pela rede. As strings são sempre transmitidas como UTF16 pela rede. 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 .

VintfEstabilidade

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 entre fornecedores de sistemas.

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 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 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 tipos anotados com VintfStability só podem ser construídos usando o tipo de módulo aidl_interface Soong, com a propriedade 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 está acessível para aplicativos legados. 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 ambiente autônomo para back-ends nã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 backend CPP, o acima emite uma classe enum C++ do tipo int32_t .

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

Se a anotação for omitida, o type será assumido como byte , que mapeia para int8_t para o back-end do CPP.

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

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

NdkOnlyStableParcelável

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

Para usar este parcelable: * Você deve especificar ndk_header . * Você deve ter uma biblioteca NDK especificando o parcelable e a biblioteca deve ser compilada na biblioteca. Por exemplo, no sistema de compilação 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 .

JavaOnlyStableParcelável

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

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 fonte 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 que você está referenciando já estiver 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 parcelados 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}

JavaPadrão

JavaDefault , adicionado no Android 13, 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)")

tornar-se

@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 algum erro de sintaxe no nível 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 é autônoma para back-ends não Java.

Tamanho fixo

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

Isso não fornece 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 Descriptor estiver faltando, o descritor será android.foo.IHello .

Isto é ú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.

@ocultar nos comentários

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

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