HIDL en C++

Android 8 rediseña el SO Android para definir interfaces claras entre plataforma de Android independiente del dispositivo y código específico para el dispositivo y el proveedor. Android ya define muchas de esas interfaces en la forma de interfaces HAL, definidos como encabezados de C en hardware/libhardware. El HIDL los reemplaza Interfaces de HAL con interfaces estables con control de versiones, que pueden ser de cliente interfaces HIDL del servidor en C++ (como se describen a continuación) Java.

En las páginas de esta sección, se describen las implementaciones de C++ de las interfaces HIDL. incluidos los detalles sobre los archivos generados automáticamente a partir del .hal de HIDL archivos por el compilador hidl-gen, la forma en que se empaquetan estos archivos y cómo integrar esos archivos con el código de C++ que los usa.

Implementaciones de cliente y servidor

Las interfaces HIDL tienen implementaciones de cliente y servidor:

  • Un cliente de una interfaz HIDL es el código que usa el a través de una llamada a los métodos en ella.
  • Un servidor es una implementación de una interfaz HIDL que recibe llamadas de los clientes y devuelve resultados (si es necesario).

En la transición de HAL de libhardware a HAL de HIDL, la HAL se convierte en el servidor, y el proceso que llama a la HAL pasa a ser al cliente. Las implementaciones predeterminadas pueden entregar contenido de transferencia y enlazado y pueden cambiar con el tiempo:

Figura 1: Progreso del desarrollo de HAL heredadas.

Crea el cliente HAL

Para comenzar, incluye las bibliotecas HAL en el archivo makefile:

  • Marca: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Soong: shared_libs: [ …, android.hardware.nfc@1.0 ]

Luego, incluye los archivos de encabezado de la HAL:

#include <android/hardware/nfc/1.0/IFoo.h>
…
// in code:
sp<IFoo> client = IFoo::getService();
client->doThing();

Cómo crear el servidor de HAL

Para crear la implementación de HAL, debes tener los archivos .hal que representan tu HAL y ya generaron archivos makefile para tu HAL usando -Lmakefile o -Landroidbp en hidl-gen (./hardware/interfaces/update-makefiles.sh hace esto para usuarios HAL y es una buena referencia). Cuando se transfieren HALs desde libhardware, puedes realizar muchos de estos trabajos de manera sencilla con c2hal.

Si quieres crear los archivos necesarios para implementar la HAL, haz lo siguiente:

PACKAGE=android.hardware.nfc@1.0
LOC=hardware/interfaces/nfc/1.0/default/
m -j hidl-gen
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE

Para que la HAL funcione en el modo de transferencia, debes tener la función HIDL_FETCH_IModuleName que reside en /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so donde OPTIONAL_IDENTIFIER es una cadena que identifica la transferencia. para implementarlos. Los requisitos del modo de transferencia se cumplen automáticamente anteriores, que también crean el android.hardware.nfc@1.0-impl pero se puede usar cualquier extensión. Por ejemplo: android.hardware.nfc@1.0-impl-foo usa -foo para diferenciarse del resto.

Si una HAL es una versión secundaria o una extensión de otra HAL, se debe usar la HAL de base para asignar un nombre a este objeto binario. Por ejemplo: Las implementaciones de android.hardware.graphics.mapper@2.1 deben todavía estar en un objeto binario llamado android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER) Por lo general, la OPTIONAL_IDENTIFIER de aquí incluiría la HAL real versión. Al nombrar el objeto binario de esta manera, los clientes 2.0 pueden recuperarlo directamente, y los clientes 2.1 pueden mejorar la implementación.

A continuación, completa los stubs con funcionalidad y configura un daemon. Ejemplo Código daemon (compatible con transferencia):

#include <hidl/LegacySupport.h>

int main(int /* argc */, char* /* argv */ []) {
    return defaultPassthroughServiceImplementation<INfc>("nfc");
}

defaultPassthroughServiceImplementation llamada dlopen() para la biblioteca -impl proporcionada y la proporciona como un servicio vinculado. Ejemplo de código de daemon (para un servicio vinculado puro):

int main(int /* argc */, char* /* argv */ []) {
    // This function must be called before you join to ensure the proper
    // number of threads are created. The threadpool never exceeds
    // size one because of this call.
    ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);

    sp<INfc> nfc = new Nfc();
    const status_t status = nfc->registerAsService();
    if (status != ::android::OK) {
        return 1; // or handle error
    }

    // Adds this thread to the threadpool, resulting in one total
    // thread in the threadpool. We could also do other things, but
    // would have to specify 'false' to willJoin in configureRpcThreadpool.
    ::android::hardware::joinRpcThreadpool();
    return 1; // joinRpcThreadpool should never return
}

Este daemon suele vivir en $PACKAGE + "-service-suffix" (durante por ejemplo, android.hardware.nfc@1.0-service), pero podría estar en cualquier lugar. La sepolicy para una configuración de HAL es el atributo hal_<module> (por ejemplo, hal_nfc) Este atributo debe aplicarse al daemon que ejecuta un HAL específica (si el mismo proceso entrega varias HAL, varios atributos se les puede aplicar).