Idioma del AIDL

El lenguaje AIDL se basa en líneas generales en el lenguaje Java. Los archivos especifican un contrato de interfaz y varios tipos de datos y constantes que se usan en este contrato.

Paquete

Cada archivo AIDL comienza con un paquete opcional que corresponde a los nombres de los paquetes en varios backends. Una declaración de paquete se ve de la siguiente manera:

    package my.package;

Al igual que Java, los archivos AIDL deben estar en una estructura de carpetas que coincida con su paquete. Los archivos con el paquete my.package deben estar en la carpeta my/package/.

Tipos

En los archivos AIDL, hay muchos lugares en los que se pueden especificar los tipos. Para obtener una lista exacta de los tipos compatibles con el lenguaje AIDL, consulta Tipos de backends de AIDL.

Anotaciones

Varias partes del lenguaje AIDL admiten anotaciones. Para obtener una lista de las anotaciones y dónde se pueden aplicar, consulta Anotaciones de AIDL.

Importaciones

Para usar los tipos definidos en otras interfaces, primero debes agregar dependencias en el sistema de compilación. En los módulos Soong cc_* y java_*, en los que los archivos .aidl se usan directamente en srcs en compilaciones de la plataforma de Android, puedes agregar directorios con el campo aidl: { include_dirs: ... }. Para las importaciones con aidl_interface, consulta aquí.

Una importación se ve de la siguiente manera:

    import some.package.Foo;  // explicit import

Cuando importas un tipo en el mismo paquete, se puede omitir el paquete. Sin embargo, omitir el paquete puede generar errores de importación ambiguos cuando los tipos se especifican sin un paquete y se colocan en el espacio de nombres global (por lo general, todos los tipos deben tener espacio de nombres):

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

Define los tipos

Por lo general, los archivos AIDL definen tipos que se usan como interfaz.

Interfaces

Este es un ejemplo de interfaz de 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();
    }

Una interfaz define un objeto con una serie de métodos. Los métodos pueden ser oneway (oneway void doFoo()) o síncronos. Si una interfaz se define como oneway (oneway interface ITeleport {...}), todos los métodos que contiene son oneway de forma implícita. Los métodos unidireccionales se despachan de forma asíncrona y no pueden mostrar un resultado. Los métodos unidireccionales del mismo subproceso al mismo Binder también se ejecutan de forma serial (aunque potencialmente en diferentes subprocesos). Para obtener información sobre cómo configurar subprocesos, consulta Administración de subprocesos de backends de AIDL.

Binder permite que se compartan muchas interfaces y objetos de Binder a través de sus interfaces. Las interfaces del AIDL con frecuencia emplean devoluciones de llamada como parte de las llamadas de método, como con ITeleportCallback en el ejemplo anterior. Puedes volver a usar objetos de devolución de llamada entre llamadas al mismo método o llamadas a diferentes métodos. Otro uso común de los tipos de interfaz es que las subinterfaces o los objetos de sesión se muestren desde métodos como con ITeleportSession en el ejemplo anterior. Este anidamiento permite que se encapsulen diferentes APIs en la API o en función del estado del entorno de ejecución. Por ejemplo, una sesión puede representar la propiedad de un recurso en particular. Cuando las interfaces se pasan varias veces o se devuelven al cliente o servidor de donde provienen, siempre conservan la igualdad de punteros del objeto Binder subyacente.

Los métodos pueden tener cero o más argumentos. Los argumentos de los métodos pueden ser in, out o inout. Para obtener información sobre cómo esto afecta a los tipos de argumentos, consulta Direccionalidad de los backends de AIDL.

Objetos parcelables

Para obtener una descripción de cómo crear objetos parcelables específicos del backend, consulta Objetos parcelables personalizados de backends de AIDL.

Android 10 y versiones posteriores admiten definiciones parcelables directamente en AIDL. Este tipo de elemento parcelable se denomina elemento parcelable estructurado. Para obtener más información sobre cómo se relacionan el AIDL estructurado y estable en el compilador de AIDL y nuestro sistema de compilación, consulta AIDL estructurado y estable.

Por ejemplo:

    package my.package;

    import my.package.Boo;

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

Uniones

Android 12 y las versiones posteriores admiten declaraciones de unión etiquetadas. Por ejemplo:

    package my.package;

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

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

Consulta Uniones de backends de AIDL para obtener detalles específicos del backend.

Enums

Android 11 y las versiones posteriores admiten declaraciones de enum. Por ejemplo:

    package my.package;

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

Declaraciones de tipos anidadas

Android 13 y las versiones posteriores admiten declaraciones de tipos anidados. Por ejemplo:

    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

Las interfaces, los elementos parcelables y las uniones de AIDL personalizadas también pueden contener constantes de números enteros y cadenas, como las siguientes:

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

Expresiones constantes

Las constantes, los tamaños de array y los enumeradores de AIDL se pueden especificar con expresiones constantes. Las expresiones pueden usar paréntesis para anidar operaciones. Los valores de expresión constante se pueden usar con valores integrales o flotantes.

Los literales true y false representan valores booleanos. Los valores con un ., pero sin sufijo, como 3.8, se consideran valores dobles. Los valores de número de punto flotante tienen el sufijo f, como 2.4f. Un valor integral con el sufijo l o L indica un valor de 64 bits. De lo contrario, los valores integrales obtienen el tipo de firma más pequeño que preserva el valor entre 8 bits (byte), 32 bits (int) y 64 bits (largo). Por lo tanto, 256 se considera un int, pero 255 + 1 se desborda para ser el byte 0. Los valores hexadecimales, como 0x3, primero se interpretan como el tipo sin firmar más pequeño que conserva el valor entre 32 y 64 bits y, luego, se reinterpretan como valores sin firmar. Por lo tanto, 0xffffffff tiene el valor int -1. A partir de Android 13, se puede agregar el sufijo u8 a constantes, como 3u8, para representar un valor byte. Este sufijo es importante para que un cálculo, como 0xffu8 * 3, se interprete como -3 con el tipo byte, mientras que 0xff * 3 es 765 con el tipo int.

Los operadores admitidos tienen semántica de C++ y Java. En orden de prioridad de la más baja a la más alta, los operadores binarios son || && | ^ & == != < > <= >= << >> + - * / %. Los operadores unarios son + - ! ~.