Android 11 introduce la capacidad de usar AIDL para las HALs en Android, lo que permite implementar partes de Android sin HIDL. Realiza la transición de las HALs para que usen AIDL exclusivamente siempre que sea posible (cuando las HALs upstream usen HIDL, se debe usar HIDL).
Los HALs que usan AIDL para comunicarse entre los componentes del framework, como los de system.img, y los componentes de hardware, como los de vendor.img, deben usar AIDL estable. Sin embargo, para comunicarse dentro de una partición, por ejemplo, de un HAL a otro, no hay restricciones sobre el mecanismo de IPC que se debe usar.
Motivación
AIDL existe desde hace más tiempo que HIDL y se usa en muchos otros lugares, como entre los componentes del framework de Android o en las apps. Ahora que AIDL admite la estabilidad, es posible implementar una pila completa con un solo tiempo de ejecución de IPC. AIDL también tiene un mejor sistema de control de versiones que HIDL. Estas son algunas ventajas de AIDL:
- Usar un solo lenguaje de IPC significa que solo hay una cosa que aprender, depurar, optimizar y proteger.
 - AIDL admite el control de versiones in situ para los propietarios de una interfaz:
- Los propietarios pueden agregar métodos al final de las interfaces o campos a los objetos parcelables. Esto significa que es más fácil controlar las versiones del código a lo largo de los años y que el costo anual también es menor (los tipos se pueden modificar en el lugar y no es necesario tener bibliotecas adicionales para cada versión de la interfaz).
 - Las interfaces de extensión se pueden adjuntar en el tiempo de ejecución en lugar de en el sistema de tipos, por lo que no es necesario volver a basar las extensiones descendentes en versiones más recientes de las interfaces.
 
 - Se puede usar directamente una interfaz de AIDL existente cuando su propietario decide estabilizarla. Antes, se debía crear una copia completa de la interfaz en HIDL.
 
Compila en el tiempo de ejecución de AIDL
AIDL tiene tres backends diferentes: Java, NDK y CPP. Para usar AIDL estable, siempre usa la copia del sistema de libbinder en system/lib*/libbinder.so y habla en /dev/binder. Para el código en la imagen vendor, esto significa que no se puede usar libbinder (del VNDK): esta biblioteca tiene una API de C++ inestable y elementos internos inestables. En cambio, el código nativo del proveedor debe usar el backend del NDK de AIDL, vincularse con libbinder_ndk (que está respaldado por libbinder.so del sistema) y vincularse con las bibliotecas del NDK creadas por las entradas de aidl_interface. Para conocer los nombres exactos de los módulos, consulta Reglas de nomenclatura de módulos.
Escribe una interfaz de HAL de AIDL
Para que se pueda usar una interfaz de AIDL entre el sistema y el proveedor, la interfaz necesita dos cambios:
- Cada definición de tipo debe anotarse con 
@VintfStability. - La declaración 
aidl_interfacedebe incluirstability: "vintf",. 
Solo el propietario de una interfaz puede realizar estos cambios.
Cuando realices estos cambios, la interfaz debe estar en el manifiesto de VINTF para que funcione. Prueba esto (y los requisitos relacionados, como verificar que las interfaces lanzadas estén congeladas) con la prueba del paquete de pruebas del proveedor (VTS) vts_treble_vintf_vendor_test. Puedes usar una interfaz @VintfStability sin estos requisitos llamando a AIBinder_forceDowngradeToLocalStability en el backend del NDK, android::Stability::forceDowngradeToLocalStability en el backend de C++ o android.os.Binder#forceDowngradeToSystemStability en el backend de Java en un objeto de vinculador antes de que se envíe a otro proceso.
Además, para lograr la máxima portabilidad del código y evitar posibles problemas, como bibliotecas adicionales innecesarias, inhabilita el backend de C++.
El código muestra cómo inhabilitar el backend de C++:
    aidl_interface: {
        ...
        backend: {
            cpp: {
                enabled: false,
            },
        },
    }
Cómo encontrar interfaces de HAL de AIDL
Las interfaces AIDL estables del AOSP para HAL se encuentran en carpetas aidl en los mismos directorios base que las interfaces HIDL:
hardware/interfaceses para interfaces que suelen proporcionar el hardware.frameworks/hardware/interfaceses para las interfaces de alto nivel que se proporcionan al hardware.system/hardware/interfaceses para las interfaces de bajo nivel que se proporcionan al hardware.
Coloca las interfaces de extensión en otros subdirectorios hardware/interfaces en vendor o hardware.
Interfaces de extensión
Android tiene un conjunto de interfaces oficiales del AOSP con cada versión. Cuando los socios de Android desean agregar capacidades a estas interfaces, no deben cambiarlas directamente, ya que esto hace que su tiempo de ejecución de Android sea incompatible con el tiempo de ejecución de Android del AOSP. Evita cambiar estas interfaces para que la imagen de la GSI pueda seguir funcionando.
Las extensiones pueden registrarse de dos maneras diferentes:
- En el tiempo de ejecución. Consulta Interfaces de extensiones adjuntas.
 - Como un elemento independiente, registrado a nivel global y en VINTF
 
Sin embargo, cuando los componentes específicos del proveedor (es decir, que no forman parte del AOSP upstream) usan la interfaz, no son posibles los conflictos de combinación. Sin embargo, cuando se realizan modificaciones downstream en los componentes del AOSP upstream, pueden producirse conflictos de combinación, por lo que se recomiendan las siguientes estrategias:
- En la próxima versión, se agregarán las interfaces al AOSP.
 - Se agregaron interfaces upstream que permiten mayor flexibilidad (sin conflictos de combinación) en la próxima versión.
 
Objetos Parcelable de extensión: ParcelableHolder
ParcelableHolder es una instancia de la interfaz Parcelable que puede contener otra instancia de Parcelable.
El caso de uso principal de ParcelableHolder es hacer que Parcelable sea extensible.
Por ejemplo, imagina que los implementadores de dispositivos esperan poder extender un Parcelable, AospDefinedParcelable, definido por el AOSP para incluir sus funciones de valor agregado.
Usa la interfaz ParcelableHolder para extender Parcelable con tus funciones de valor agregado. La interfaz ParcelableHolder contiene una instancia de Parcelable. Si intentas agregar campos a Parcelable directamente, se producirá un error:
parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}
Como se ve en el código anterior, esta práctica no se cumple porque los campos agregados por el implementador del dispositivo podrían tener un conflicto cuando se revise Parcelable en las próximas versiones de Android.
Con ParcelableHolder, el propietario de un objeto Parcelable puede definir un punto de extensión en una instancia de Parcelable:
parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}
Luego, los implementadores de dispositivos pueden definir su propia instancia de Parcelable para su extensión:
parcelable OemDefinedParcelable {
  String x;
  int[] y;
}
La nueva instancia de Parcelable se puede adjuntar al Parcelable original con el campo ParcelableHolder:
// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;
ap.extension.setParcelable(op);
...
OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);
// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();
ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);
...
std::shared_ptr<OemDefinedParcelable> op_ptr;
ap.extension.getParcelable(&op_ptr);
// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);
...
std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);
// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });
ap.extension.set_parcelable(Rc::clone(&op));
...
let op = ap.extension.get_parcelable::<OemDefinedParcelable>();
Nombres de instancias del servidor HAL de AIDL
Por convención, los servicios de HAL de AIDL tienen un nombre de instancia con el formato $package.$type/$instance. Por ejemplo, una instancia del HAL del vibrador se registra como android.hardware.vibrator.IVibrator/default.
Escribe un servidor HAL de AIDL
Los servidores AIDL @VintfStability se deben declarar en el manifiesto de VINTF, por ejemplo:
    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>
De lo contrario, deben registrar un servicio de AIDL de forma normal. Cuando se ejecutan pruebas de VTS, se espera que todos los HAL de AIDL declarados estén disponibles.
Cómo escribir un cliente de AIDL
Los clientes de AIDL deben declararse en la matriz de compatibilidad, por ejemplo:
    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>
Cómo convertir una HAL existente de HIDL a AIDL
Usa la herramienta hidl2aidl para convertir una interfaz de HIDL a AIDL.
Funciones de hidl2aidl:
- Crea archivos AIDL (
.aidl) basados en los archivos HAL (.hal) para el paquete determinado. - Crea reglas de compilación para el paquete AIDL recién creado con todos los backends habilitados.
 - Crea métodos de traducción en los backends de Java, C++ y NDK para traducir de los tipos de HIDL a los tipos de AIDL.
 - Crea reglas de compilación para las bibliotecas de traducción con las dependencias requeridas.
 - Crea aserciones estáticas para garantizar que los enumeradores de HIDL y AIDL tengan los mismos valores en los backends de C++ y NDK.
 
Sigue estos pasos para convertir un paquete de archivos HAL en archivos AIDL:
Compila la herramienta ubicada en
system/tools/hidl/hidl2aidl.Compilar esta herramienta desde la fuente más reciente proporciona la experiencia más completa. Puedes usar la versión más reciente para convertir interfaces en ramas más antiguas de versiones anteriores:
m hidl2aidlEjecuta la herramienta con un directorio de salida seguido del paquete que se convertirá.
De manera opcional, usa el argumento
-lpara agregar el contenido de un archivo de licencia nuevo en la parte superior de todos los archivos generados. Asegúrate de usar la licencia y la fecha correctas:hidl2aidl -o <output directory> -l <file with license> <package>Por ejemplo:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2Lee los archivos generados y corrige cualquier problema con la conversión:
conversion.logcontiene los problemas no controlados que debes solucionar primero.- Es posible que los archivos AIDL generados tengan advertencias y sugerencias que requieran acción. Estos comentarios comienzan con 
//. - Limpia y mejora el paquete.
 - Verifica la anotación 
@JavaDerivepara las funciones que podrían ser necesarias, comotoStringoequals. 
Compila solo los destinos que necesitas:
- Inhabilita los backends que no se usarán. Prefiere el backend del NDK al backend de C++; consulta Cómo compilar en el tiempo de ejecución de AIDL.
 - Quita las bibliotecas de traducción o cualquier código generado que no se use.
 
Consulta las principales diferencias entre AIDL y HIDL:
- Por lo general, usar 
Statusy excepciones integradas en AIDL mejora la interfaz y elimina la necesidad de otro tipo de estado específico de la interfaz. - Los argumentos de la interfaz de AIDL en los métodos no son 
@nullablede forma predeterminada, como lo eran en HIDL. 
- Por lo general, usar 
 
SEPolicy para HALs de AIDL
Un tipo de servicio de AIDL que es visible para el código del proveedor debe tener el atributo hal_service_type. De lo contrario, la configuración de sepolicy es la misma que la de cualquier otro servicio de AIDL (aunque hay atributos especiales para los HALs). Este es un ejemplo de definición de un contexto de servicio de HAL:
    type hal_foo_service, service_manager_type, hal_service_type;
En el caso de la mayoría de los servicios definidos por la plataforma, ya se agrega un contexto de servicio con el tipo correcto (por ejemplo, android.hardware.foo.IFoo/default ya está marcado como hal_foo_service). Sin embargo, si un cliente de framework admite varios nombres de instancias, se deben agregar nombres de instancias adicionales en los archivos service_contexts específicos del dispositivo:
    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0
Cuando creas un nuevo tipo de HAL, debes agregar atributos de HAL. Un atributo HAL específico se puede asociar con varios tipos de servicios (cada uno de los cuales puede tener varias instancias, como se acaba de mencionar). Para un HAL, foo, hay hal_attribute(foo). Esta macro define los atributos hal_foo_client y hal_foo_server. Para un dominio determinado, las macros hal_client_domain y hal_server_domain asocian un dominio con un atributo HAL determinado. Por ejemplo, el servidor del sistema que es cliente de este HAL corresponde a la política hal_client_domain(system_server, hal_foo). De manera similar, un servidor HAL incluye hal_server_domain(my_hal_domain, hal_foo).
Por lo general, para un atributo de HAL determinado, también se crea un dominio como hal_foo_default para HALs de referencia o de ejemplo. Sin embargo, algunos dispositivos usan estos dominios para sus propios servidores. Distinguir entre dominios para varios servidores solo importa si hay varios servidores que publican la misma interfaz y necesitan un conjunto de permisos diferente en sus implementaciones.
En todas estas macros, hal_foo no es un objeto de sepolicy. En cambio, estas macros usan este token para hacer referencia al grupo de atributos asociados con un par de servidor y cliente.
Sin embargo, hasta el momento, hal_foo_service y hal_foo (el par de atributos de hal_attribute(foo)) no están asociados. Un atributo de HAL se asocia con los servicios de HAL de AIDL a través de la macro hal_attribute_service (las HAL de HIDL usan la macro hal_attribute_hwservice), por ejemplo, hal_attribute_service(hal_foo, hal_foo_service). Esto significa que los procesos de hal_foo_client pueden acceder al HAL y los procesos de hal_foo_server pueden registrar el HAL. El administrador de contexto (servicemanager) aplica estas reglas de registro.
Es posible que los nombres de los servicios no siempre correspondan a los atributos de HAL, por ejemplo, hal_attribute_service(hal_foo, hal_foo2_service). En general, dado que esto implica que los servicios siempre se usan juntos, puedes quitar hal_foo2_service y usar hal_foo_service para todos los contextos de servicio. Cuando los HAL establecen varias instancias de hal_attribute_service, se debe a que el nombre del atributo del HAL original no es lo suficientemente general y no se puede cambiar.
Si se junta todo, un ejemplo de HAL se ve de la siguiente manera:
    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)
    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type
    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)
    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0
    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)
    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)
Interfaces de extensión adjuntas
Una extensión se puede adjuntar a cualquier interfaz de Binder, ya sea una interfaz de nivel superior registrada directamente con el administrador de servicios o una subinterfaz. Cuando obtengas una extensión, debes confirmar que el tipo de extensión sea el esperado. Solo puedes configurar extensiones desde el proceso que publica un binder.
Usa extensiones adjuntas siempre que una extensión modifique la funcionalidad de un HAL existente. Cuando se necesita una capacidad completamente nueva, este mecanismo no es necesario y puedes registrar una interfaz de extensión directamente con el administrador de servicios. Las interfaces de extensión adjuntas tienen más sentido cuando se adjuntan a subinterfaces, ya que estas jerarquías pueden ser profundas o tener varias instancias. Usar una extensión global para duplicar la jerarquía de la interfaz del vinculador de otro servicio requiere una contabilidad exhaustiva para proporcionar capacidades equivalentes a las extensiones adjuntas directamente.
Para establecer una extensión en un vinculador, usa las siguientes APIs:
- Backend del NDK: 
AIBinder_setExtension - Backend de Java: 
android.os.Binder.setExtension - Backend de CPP: 
android::Binder::setExtension - Backend de Rust: 
binder::Binder::set_extension 
Para obtener una extensión en un binder, usa las siguientes APIs:
- Backend del NDK: 
AIBinder_getExtension - Backend de Java: 
android.os.IBinder.getExtension - Backend de CPP: 
android::IBinder::getExtension - Backend de Rust: 
binder::Binder::get_extension 
Puedes encontrar más información sobre estas APIs en la documentación de la función getExtension en el backend correspondiente. En hardware/interfaces/tests/extension/vibrator, se muestra un ejemplo de cómo usar extensiones.
Diferencias principales entre AIDL y HIDL
Cuando uses HALs de AIDL o interfaces de HAL de AIDL, ten en cuenta las diferencias en comparación con la escritura de HALs de HIDL.
- La sintaxis del lenguaje AIDL es más similar a la de Java. La sintaxis de HIDL es similar a la de C++.
 - Todas las interfaces de AIDL tienen estados de error integrados. En lugar de crear tipos de estado personalizados, crea ints de estado constantes en los archivos de interfaz y usa 
EX_SERVICE_SPECIFICen los backends de C++ y NDK, yServiceSpecificExceptionen el backend de Java. Consulta Manejo de errores. - AIDL no inicia automáticamente grupos de subprocesos cuando se envían objetos de Binder. Debes iniciarlos de forma manual (consulta Administración de subprocesos).
 - AIDL no anula la operación en caso de errores de transporte no verificados (HIDL 
Returnanula la operación en caso de errores no verificados). - AIDL solo puede declarar un tipo por archivo.
 - Los argumentos de AIDL se pueden especificar como 
in,outoinout, además del parámetro de salida (no hay devoluciones de llamada síncronas). - AIDL usa 
fdcomo el tipo primitivo en lugar dehandle. - HIDL usa versiones principales para los cambios incompatibles y versiones secundarias para los cambios compatibles. En AIDL, los cambios compatibles con versiones anteriores se realizan en el lugar.
AIDL no tiene un concepto explícito de versiones principales; en cambio, esto se incorpora en los nombres de los paquetes. Por ejemplo, AIDL podría usar el nombre de paquete 
bluetooth2. - De forma predeterminada, AIDL no hereda la prioridad en tiempo real. La función 
setInheritRtse debe usar por vinculador para habilitar la herencia de prioridad en tiempo real. 
Pruebas para HALs
En esta sección, se describen las prácticas recomendadas para probar los HALs. Estas prácticas son válidas incluso si la prueba de integración de tu HAL no está en VTS.
Android depende del VTS para verificar las implementaciones de HAL esperadas. El VTS ayuda a garantizar que Android pueda ser retrocompatible con implementaciones de proveedores anteriores. Las implementaciones que no superan las VTS tienen problemas de compatibilidad conocidos que podrían impedir que funcionen con versiones futuras del SO.
VTS para HAL tiene dos partes principales.
1. Verifica que Android conozca y espere los HAL del dispositivo
Android depende de tener una lista estática y precisa de todos los HALs instalados. Esta lista se expresa en el manifiesto de VINTF. Las pruebas especiales en toda la plataforma verifican la integridad de las capas del HAL en todo el sistema. Antes de escribir cualquier prueba específica del HAL, también debes ejecutar estas pruebas, ya que pueden indicar si un HAL tiene configuraciones de VINTF incoherentes.
Este conjunto de pruebas se puede encontrar en test/vts-testcase/hal/treble/vintf. Si trabajas en la implementación de un HAL del proveedor, usa vts_treble_vintf_vendor_test para verificarlo. Puedes ejecutar esta prueba con el comando atest vts_treble_vintf_vendor_test.
Estas pruebas son responsables de verificar lo siguiente:
- Cada interfaz 
@VintfStabilityque se declara en un manifiesto de VINTF se inmoviliza en una versión lanzada conocida. Esto verifica que ambos lados de la interfaz coincidan en la definición exacta de esa versión de la interfaz. Esto es necesario para el funcionamiento básico. - Todos los HAL declarados en un manifiesto de VINTF están disponibles en ese dispositivo. Cualquier cliente con permisos suficientes para usar un servicio HAL declarado debe poder obtener y usar esos servicios en cualquier momento.
 - Todos los HAL declarados en un manifiesto de VINTF publican la versión de la interfaz que declaran en el manifiesto.
 - No se publican HALs obsoletos en un dispositivo. Android deja de admitir versiones anteriores de las interfaces HAL, como se describe en el ciclo de vida de FCM.
 - Los HALs requeridos están presentes en el dispositivo. Algunos HAL son necesarios para que Android funcione correctamente.
 
2. Verifica el comportamiento esperado de cada HAL
Cada interfaz de HAL tiene sus propias pruebas de VTS para verificar el comportamiento esperado de sus clientes. Los casos de prueba se ejecutan en cada instancia de una interfaz HAL declarada y aplican un comportamiento específico según la versión de la interfaz que se implementa.
En C++, puedes obtener una lista de cada HAL instalado en el sistema con la función android::getAidlHalInstanceNames en libaidlvintf_gtest_helper. En Rust, usa binder::get_declared_instances.
Estas pruebas intentan abarcar todos los aspectos de la implementación del HAL en los que se basa el framework de Android o en los que podría basarse en el futuro.
Estas pruebas incluyen la verificación de la compatibilidad con las funciones, el control de errores y cualquier otro comportamiento que un cliente podría esperar del servicio.
Hitos de VTS para el desarrollo de HAL
Se espera que las pruebas de VTS (o cualquier prueba) se mantengan actualizadas cuando se creen o modifiquen las interfaces HAL de Android.
Las pruebas de VTS deben finalizarse y estar listas para verificar las implementaciones del proveedor antes de que se congelen para los lanzamientos de la API de Android Vendor. Deben estar listas antes de que se congelen las interfaces para que los desarrolladores puedan crear sus implementaciones, verificarlas y proporcionar comentarios a los desarrolladores de la interfaz de HAL.
Cómo probar en Cuttlefish
Cuando el hardware no está disponible, Android usa Cuttlefish como vehículo de desarrollo para las interfaces HAL. Esto permite realizar pruebas de integración escalables de Android.
hal_implementation_test prueba que Cuttlefish tenga implementaciones de las versiones de interfaz HAL más recientes para asegurarse de que Android esté listo para controlar las nuevas interfaces y que las pruebas de VTS estén listas para probar las nuevas implementaciones del proveedor en cuanto haya hardware y dispositivos nuevos disponibles.