Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

AIDL para HAL

Android 11 presenta la capacidad de usar AIDL para HAL en Android. Esto hace posible implementar partes de Android sin HIDL. Haga la transición de los HAL para usar AIDL exclusivamente cuando sea posible (cuando los HAL ascendentes usen HIDL, se debe usar HIDL).

HAL utilizando AIDL para comunicarse entre los componentes estructurales, tales como los de system.img y componentes de hardware, tales como los de vendor.img , debe utilizar AIDL estable. Sin embargo, para comunicarse dentro de una partición, por ejemplo, de un HAL a otro, no hay restricciones en el mecanismo de IPC para usar.

Motivación

AIDL ha existido por más tiempo que HIDL y se usa en muchos otros lugares, como entre componentes del marco de Android o en aplicaciones. Ahora que AIDL tiene soporte de 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.

  • Usar un solo lenguaje de IPC significa tener solo una cosa que aprender, depurar, optimizar y asegurar.
  • 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 parcelables. Esto significa que es más fácil versionar el código a lo largo de los años, y también el costo anual es menor (los tipos se pueden modificar en el lugar y no hay necesidad de bibliotecas adicionales para cada versión de la interfaz).
    • Las interfaces de extensión se pueden adjuntar en tiempo de ejecución en lugar de en el sistema de tipos, por lo que no es necesario volver a basar las extensiones posteriores en versiones más nuevas de las interfaces.
  • Una interfaz AIDL existente se puede utilizar directamente cuando su propietario elige estabilizarla. Antes, se tendría que crear una copia completa de la interfaz en HIDL.

Escribir una interfaz AIDL HAL

Para que se utilice una interfaz AIDL entre el sistema y el proveedor, la interfaz necesita dos cambios:

  • Cada definición de tipo debe ser anotado con @VintfStability .
  • El aidl_interface declaración debe incluir stability: "vintf", .

Solo el propietario de una interfaz puede realizar estos cambios.

Al realizar estos cambios, la interfaz debe estar en el manifiesto VINTF con el fin de trabajo. Probar esta (y afines requisitos, tales como la verificación de que las interfaces liberados son congelados) utilizando la prueba de VTS vts_treble_vintf_vendor_test . Puede utilizar un @VintfStability interfaz sin estos requisitos, ya sea llamando AIBinder_forceDowngradeToLocalStability en el backend NDK, android::Stability::forceDowngradeToLocalStability en el back-end C ++, o android.os.Binder#forceDowngradeToSystemStability en el back-end de Java en un objeto de aglutinante antes de que se envíe a otro proceso. La degradación de un servicio a la estabilidad del proveedor no es compatible con Java porque todas las aplicaciones se ejecutan en un contexto de sistema.

Además, para una máxima portabilidad del código y para evitar problemas potenciales como bibliotecas adicionales innecesarias, desactive el backend de CPP.

Tenga en cuenta que el uso de backends en el siguiente ejemplo de código es correcto, ya que hay tres backends (Java, NDK, y CPP). El siguiente código le dice cómo seleccionar el backend de CPP específicamente, para deshabilitarlo.

    aidl_interface: {
        ...
        backends: {
            cpp: {
                enabled: false,
            },
        },
    }

Encontrar interfaces AIDL HAL

AOSP interfaces de AIDL estables para HAL están en los mismos directorios base como interfaces HIDL, en aidl carpetas.

  • hardware / interfaces
  • frameworks / hardware / interfaces
  • sistema / hardware / interfaces

Usted debe poner interfaces de extensión a otros hardware/interfaces subdirectorios de vendor o hardware .

Interfaces de extensión

Android tiene un conjunto de interfaces AOSP oficiales con cada lanzamiento. Cuando los socios de Android desean agregar funcionalidad a estas interfaces, no deben cambiarlas directamente porque esto significaría que su tiempo de ejecución de Android es incompatible con el tiempo de ejecución de Android AOSP. Para los dispositivos GMS, evitar cambiar estas interfaces también es lo que garantiza que la imagen GSI pueda seguir funcionando.

Las extensiones se pueden registrar de dos formas diferentes:

  • en tiempo de ejecución, consulte extensiones adjunta .
  • autónomo, registrado globalmente y en VINTF.

Sin embargo, se registra una extensión, cuando los componentes específicos del proveedor (es decir, que no forman parte de AOSP ascendente) utilizan la interfaz, no hay posibilidad de conflicto de fusión. Sin embargo, cuando se realizan modificaciones posteriores a los componentes AOSP ascendentes, pueden producirse conflictos de fusión y se recomiendan las siguientes estrategias:

  • las adiciones de interfaz se pueden transmitir a AOSP en la próxima versión
  • Las adiciones de interfaz que permiten una mayor flexibilidad, sin conflictos de fusión, se pueden transmitir en la próxima versión.

Parcelables de extensión: ParcelableHolder

ParcelableHolder es un Parcelable que puede contener otro Parcelable . El caso de uso principal del ParcelableHolder es hacer una Parcelable extensible. Por ejemplo, la imagen que los implementadores de dispositivos esperan ser capaces de extender una definida AOSP Parcelable , AospDefinedParcelable , para incluir sus características de valor añadido.

Anteriormente, sin ParcelableHolder , los ejecutores de dispositivos no podía modificar una interfaz AIDL estable AOSP definidos, ya que sería un error para añadir más campos:

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

Como se vio en el código anterior, esta práctica no funciona porque los campos agregados por el implementador del dispositivo pueden tener un conflicto cuando Parcelable se revisa en las próximas versiones de Android.

Usando ParcelableHolder , el propietario de un parcelable puede definir un punto de extensión en un Parcelable .

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

A continuación, los ejecutores de dispositivos pueden definir su propio Parcelable por su extensión.

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

Por último, el nuevo Parcelable se puede conectar a la original Parcelable a través de la ParcelableHolder campo.


// 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>();

Construyendo contra el tiempo de ejecución de AIDL

AIDL tiene tres backends diferentes: Java, NDK, CPP. Para utilizar AIDL estable, debe utilizar siempre el sistema de copia de libbinder al system/lib*/libbinder.so y hablar en /dev/binder . Para el código de la imagen vendedor en, esto significa que libbinder (de la VNDK) no se pueden utilizar: esta biblioteca tiene una C inestable ++ API y internals inestables. En su lugar, código de proveedor nativo debe utilizar el backend NDK de AIDL, enlace contra libbinder_ndk (que está respaldado por el sistema libbinder.so ), y el enlace contra las -ndk_platform bibliotecas creadas por aidl_interface entradas.

Nombres de instancias del servidor AIDL HAL

Por convención, los servicios AIDL HAL tienen un nombre de instancia del formato $package.$type/$instance . Por ejemplo, una instancia de la HAL vibrador está registrada como android.hardware.vibrator.IVibrator/default .

Escribir un servidor AIDL HAL

@VintfStability servidores AIDL deben ser declarados en el manifiesto VINTF, por ejemplo, así:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

De lo contrario, deberían registrar un servicio AIDL normalmente. Al ejecutar pruebas de VTS, se espera que todos los AIDL HAL declarados estén disponibles.

Escribir un cliente AIDL

Los clientes de AIDL deben declararse en la matriz de compatibilidad, por ejemplo así:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

Conversión de un HAL existente de HIDL a AIDL

Usar la hidl2aidl herramienta para convertir una interfaz HIDL a AIDL.

hidl2aidl características:

  • Crear .aidl archivos basándose en los .hal archivos para el paquete dado
  • Cree reglas de compilación para el paquete AIDL recién creado con todos los backends habilitados
  • Cree métodos de traducción en los backends de Java, CPP y NDK para traducir de los tipos HIDL a los tipos AIDL
  • Cree reglas de compilación para traducir bibliotecas con las dependencias necesarias
  • Cree afirmaciones estáticas para asegurarse de que los enumeradores HIDL y AIDL tengan los mismos valores en los backends de CPP y NDK

Siga estos pasos para convertir un paquete de archivos .hal a archivos .aidl:

  1. La construcción de la herramienta situada en el system/tools/hidl/hidl2aidl .

    La creación de esta herramienta a partir de la última fuente proporciona la experiencia más completa. Puede utilizar la última versión para convertir interfaces en ramas más antiguas de versiones anteriores.

    m hidl2aidl
    
  2. Ejecute la herramienta con un directorio de salida seguido del paquete a convertir.

    hidl2aidl -o <output directory> <package>
    

    Por ejemplo:

    hidl2aidl -o . android.hardware.nfc@1.2
    
  3. Lea los archivos generados y solucione cualquier problema con la conversión.

    • conversion.log contiene cualquier problema no controladas para fijar en primer lugar.
    • Los generados .aidl archivos podrían tener advertencias y sugerencias que la acción pueda necesitar. Estos comentarios comienzan con // .
    • Aproveche la oportunidad para limpiar y realizar mejoras en el paquete.
  4. Construya solo los objetivos que necesita.

    • Inhabilite los backends que no se usarán. Prefiero el backend NDK sobre el backend CPP, véase la elección de tiempo de ejecución .
    • Elimine las bibliotecas de traducción o cualquiera de sus códigos generados que no se utilizarán.
  5. Ver Major AIDL / HIDL diferencias .

    • El uso de AIDL incorporados en el Status y las excepciones suelen mejorar la interfaz y eliminan la necesidad de otro tipo de estado de la interfaz específica.

Política para AIDL HAL

Un tipo de servicio AIDL que es visible para el código de proveedor debe tener la vendor_service atributo. De lo contrario, la configuración de sepolicy es la misma que la de cualquier otro servicio AIDL.

    type hal_power_service, service_manager_type, vendor_service;

Para la mayoría de los servicios definidos por la plataforma, se añade un contexto de servicio con el tipo correcto ya (por ejemplo, android.hardware.power.IPower/default ya está marcado como hal_power_service ). Sin embargo, si un cliente marco soporta múltiples nombres de instancia, nombres de instancias adicionales deben agregarse en dispositivos específicos service_contexts archivos.

    android.hardware.power.IPower/custom_instance u:object_r:hal_power_service:s0

Interfaces de extensión adjuntas

Se puede adjuntar una extensión a cualquier interfaz de enlace, ya sea una interfaz de nivel superior registrada directamente con el administrador de servicios o una subinterfaz. Al obtener una extensión, debe confirmar que el tipo de extensión es el esperado. Las extensiones solo se pueden configurar desde el proceso que sirve a un archivador.

Las extensiones adjuntas deben usarse siempre que una extensión modifique la funcionalidad de una HAL existente. Cuando se necesita una funcionalidad completamente nueva, no es necesario utilizar este mecanismo y se puede registrar una interfaz de extensión con el administrador de servicios directamente. Las interfaces de extensión adjuntas tienen más sentido cuando se adjuntan a subinterfaces, porque estas jerarquías pueden ser profundas o con múltiples instancias. El uso de una extensión global para reflejar la jerarquía de la interfaz de enlace de otro servicio requeriría una contabilidad extensa para proporcionar una funcionalidad equivalente a las extensiones adjuntas directamente.

Para configurar una extensión en Binder, use las siguientes API:

  • En el back-end NDK: AIBinder_setExtension
  • En el back-end de Java: android.os.Binder.setExtension
  • En el back-end CPP: android::Binder::setExtension

Para obtener una extensión en una carpeta, use las siguientes API:

  • En el back-end NDK: AIBinder_getExtension
  • En el back-end de Java: android.os.IBinder.getExtension
  • En el back-end CPP: android::IBinder::getExtension

Puede encontrar más información de estas API en la documentación de la getExtension función en el servidor correspondiente. Un ejemplo de cómo usar las extensiones se pueden encontrar en el hardware / las interfaces / pruebas / extensión / vibrador .

Principales diferencias AIDL / HIDL

Cuando utilice AIDL HAL o utilice interfaces AIDL HAL, tenga en cuenta las diferencias en comparación con la escritura de HIDL HAL.

  • La sintaxis del lenguaje AIDL está más cerca de Java. La sintaxis de HIDL es similar a la de C ++.
  • Todas las interfaces AIDL tienen estados de error incorporados. En lugar de crear tipos de estado personalizados, crear enteros constantes de estado en los archivos de interfaz y el uso EX_SERVICE_SPECIFIC en los backends CPP / NDK y ServiceSpecificException en el back-end de Java. Ver Control de errores .
  • AIDL no inicia automáticamente las agrupaciones de subprocesos cuando se envían objetos de carpeta. Ellos deben iniciarse manualmente (ver manejo de hilos ).
  • AIDL no lo hace abortar en los errores de transporte sin marcar (HIDL Return aborta en errores no marcado).
  • AIDL solo puede declarar un tipo por archivo.
  • Los argumentos AIDL se pueden especificar como in / out / inout además del parámetro de salida (no hay "devoluciones de llamada síncronas").
  • AIDL usa un fd como tipo primitivo en lugar de handle.
  • HIDL usa versiones principales para cambios incompatibles y versiones menores para cambios compatibles. En AIDL, los cambios compatibles con versiones anteriores se realizan en su lugar. AIDL no tiene un concepto explícito de versiones principales; en su lugar, esto se incorpora a los nombres de los paquetes. Por ejemplo, AIDL podría usar el nombre del paquete bluetooth2 .