Linguagem AIDL

A linguagem AIDL é vagamente baseada na linguagem Java. Os arquivos especificam um contrato de interface e vários tipos de dados e constantes usados nesse contrato.

Pacote

Todos os arquivos AIDL começam com um pacote opcional que corresponde aos nomes de pacote em vários back-ends. Uma declaração de pacote tem esta aparência:

    package my.package;

Assim como no Java, os arquivos AIDL precisam estar em uma estrutura de pastas que corresponda ao pacote. Os arquivos com o pacote my.package precisam estar na pasta my/package/.

Tipos

Em arquivos AIDL, há muitos lugares em que os tipos podem ser especificados. Para conferir uma lista exata dos tipos com suporte no idioma AIDL, consulte Tipos de back-ends AIDL.

Anotações

Várias partes do idioma AIDL oferecem suporte a anotações. Para conferir uma lista de anotações e onde elas podem ser aplicadas, consulte Anotações do AIDL.

Importações

Para usar tipos definidos em outras interfaces, primeiro é necessário adicionar dependências no sistema de build. Nos módulos Soong cc_* e java_*, em que os arquivos .aidl são usados diretamente em srcs nos builds da plataforma Android, você pode adicionar diretórios usando o campo aidl: { include_dirs: ... }. Para importações que usam aidl_interface, consulte este link.

Uma importação é assim:

    import some.package.Foo;  // explicit import

Ao importar um tipo no mesmo pacote, o pacote pode ser omitido. No entanto, a omissão do pacote pode levar a erros de importação ambíguos quando os tipos são especificados sem um pacote e colocados no namespace global. Geralmente, todos os tipos precisam receber namespace:

    import Foo;  // same as my.package.Foo

Definir tipos

Os arquivos AIDL geralmente definem tipos que são usados como uma interface.

Interfaces

Confira um exemplo de interface AIDL:

    interface ITeleport {
        // Location defined elsewhere
        void teleport(Location baz, float speed);
        String getName();

        // ITeleportCallback defined elsewhere
        void methodWithCallback(ITeleportCallback callback);

        // ITeleportSession defined elsewhere
        ITeleportSession getASubInterface();
    }

Uma interface define um objeto com uma série de métodos. Os métodos podem ser oneway (oneway void doFoo()) ou síncronos. Se uma interface for definida como oneway (oneway interface ITeleport {...}), todos os métodos nela serão implicitamente oneway. Os métodos de uma via são enviados de forma assíncrona e não podem retornar um resultado. Métodos unidirecionais da mesma linha de execução para o mesmo vinculamento também são executados em série (em linhas de execução diferentes). Para saber como configurar linhas de execução, consulte Gerenciamento de linhas de execução de back-ends AIDL.

O binder permite que muitas interfaces e objetos de vinculação sejam compartilhados usando interfaces de binder. As interfaces AIDL geralmente empregam callbacks como parte das chamadas de método, como com ITeleportCallback no exemplo anterior. É possível reutilizar objetos de callback entre chamadas para o mesmo método ou para métodos diferentes. Outro uso comum de tipos de interface é que subinterfaces ou objetos de sessão sejam retornados de métodos como ITeleportSession no exemplo anterior. Esse aninhamento permite que diferentes APIs sejam encapsuladas na API ou com base no estado de execução. Por exemplo, uma sessão pode representar a propriedade de um recurso específico. Quando as interfaces são transmitidas várias vezes ou retornadas ao cliente ou servidor de origem, elas sempre preservam a igualdade de ponteiro do objeto de vinculação subjacente.

Os métodos podem ter zero ou mais argumentos. Os argumentos para os métodos podem ser in, out ou inout. Para saber como isso afeta os tipos de argumentos, consulte Direcionalidade de back-ends AIDL.

Parcelables

Para uma descrição de como criar parcelables específicos do back-end, parcelables personalizados de back-ends AIDL.

O Android 10 e versões mais recentes oferecem suporte a definições parceláveis diretamente no AIDL. Esse tipo de parcelável é chamado de parcelável estruturado. Para mais informações sobre como as AIDLs estruturadas e estáveis estão relacionadas no compilador de AIDL e no nosso sistema de build, consulte AIDL estruturada x estável.

Exemplo:

    package my.package;

    import my.package.Boo;

    parcelable Baz {
        @utf8InCpp String name = "baz";
        Boo boo;
    }

Sindicatos

O Android 12 e versões mais recentes oferecem suporte a declarações de união com tags. Exemplo:

    package my.package;

    import my.package.FooSettings;
    import my.package.BarSettings;

    union Settings {
        FooSettings fooSettings;
        BarSettings barSettings;
        @utf8InCpp String str;
        int number;
    }

Consulte Uniões de back-ends do AIDL para detalhes específicos do back-end.

Enumerações

O Android 11 e versões mais recentes oferecem suporte a declarações de tipo enumerado. Exemplo:

    package my.package;

    enum Boo {
        A = 1 * 4,
        B = 3,
    }

Declarações de tipo aninhadas

O Android 13 e versões mais recentes oferecem suporte a declarações de tipo aninhadas. Exemplo:

    package my.package;

    import my.package.Baz;

    interface IFoo {
        void doFoo(Baz.Nested nested);  // defined in my/package/Baz.aidl
        void doBar(Bar bar);            // defined below

        parcelable Bar { ... }          // nested type definition
    }

Constantes

Interfaces, parceláveis e uniões personalizadas da AIDL também podem conter constantes inteiras e de string, como:

    const @utf8InCpp String HAPPY = ":)";
    const String SAD = ":(";
    const byte BYTE_ME = 1;
    const int ANSWER = 6 * 7;

Expressões constantes

As constantes AIDL, os tamanhos de matriz e os enumeradores podem ser especificados usando expressões constantes. As expressões podem usar parênteses para aninhar operações. Valores de expressão constante podem ser usados com valores inteiros ou flutuantes.

Os literais true e false representam valores booleanos. Valores com ., mas sem um sufixo, como 3.8, são considerados valores duplos. Valores flutuantes têm o sufixo f, como 2.4f. Um valor integral com o sufixo l ou L indica um valor de 64 bits. Caso contrário, os valores integrais recebem o menor tipo assinado que preserva o valor entre 8 bits (byte), 32 bits (int) e 64 bits (long). Portanto, 256 é considerado um int, mas 255 + 1 transborda para ser o byte 0. Valores hexadecimais, como 0x3, são primeiro interpretados como o menor tipo não assinado de preservação de valor entre 32 e 64 bits e, em seguida, reinterpretados como valores não assinados. Portanto, 0xffffffff tem o valor int -1. A partir do Android 13, o sufixo u8 pode ser adicionado a constantes, como 3u8, para representar um valor byte. Esse sufixo é importante para que um cálculo, como 0xffu8 * 3, seja interpretado como -3 com o tipo byte, enquanto 0xff * 3 é 765 com o tipo int.

Os operadores compatíveis têm semântica C++ e Java. Em ordem de precedência mais baixa para mais alta, os operadores binários são || && | ^ & == != < > <= >= << >> + - * / %. Os operadores unários são + - ! ~.