Google is committed to advancing racial equity for Black communities. See how.
Se usó la API de Cloud Translation para traducir esta página.
Switch to English

HIDL C++

Android O rediseña el sistema operativo Android para definir interfaces claras entre la plataforma Android independiente del dispositivo y el código específico del dispositivo y del proveedor. Android ya define muchas de estas interfaces en forma de interfaces HAL, definidas como encabezados C en hardware/libhardware . HIDL reemplaza estas interfaces HAL con interfaces versionadas estables, que pueden ser interfaces HIDL del lado del cliente y del servidor en C ++ (descrito a continuación) o Java .

Las páginas de esta sección describen las implementaciones en C ++ de las interfaces HIDL, incluidos los detalles sobre los archivos generados automáticamente a partir de los archivos HIDL .hal por el compilador hidl-gen , cómo se empaquetan estos archivos y cómo integrar estos archivos con el código 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 la interfaz llamando a métodos en ella.
  • Un servidor es una implementación de una interfaz HIDL que recibe llamadas de clientes y devuelve resultados (si es necesario).

Al realizar la transición de libhardware HAL a HIDL HAL, la implementación de HAL se convierte en el servidor y el proceso que llama al HAL se convierte en el cliente. Las implementaciones predeterminadas pueden servir HAL de paso a través y enlazadas, y pueden cambiar con el tiempo:

Figura 1. Progresión del desarrollo para HAL heredados.

Creando el cliente HAL

Comience por incluir las bibliotecas HAL en el archivo MAKE:

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

A continuación, incluya los archivos de encabezado HAL:

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

Creando el servidor HAL

Para crear la implementación de HAL, debe tener los archivos .hal que representan su HAL y ya ha generado archivos MAKE para su HAL usando -Lmakefile o -Landroidbp en hidl-gen ( ./hardware/interfaces/update-makefiles.sh hace esto para archivos HAL internos y es una buena referencia). Al transferir HAL desde libhardware , puede hacer mucho de este trabajo fácilmente usando c2hal.

Para crear los archivos necesarios para implementar su HAL:

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 HAL funcione en modo de transferencia, debe tener la función HIDL_FETCH_IModuleName que resida en /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).so donde OPTIONAL_IDENTIFIER es una cadena que identifica la implementación de paso a través. Los requisitos del modo de paso a través se cumplen automáticamente con los comandos anteriores, que también crean el objetivo 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.

Si un HAL es una versión menor o una extensión de otro HAL, el HAL base debe usarse para nombrar este binario. Por ejemplo, las implementaciones de android.hardware.graphics.mapper@2.1 aún deben estar en un binario llamado android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Por lo general, el OPTIONAL_IDENTIFIER aquí incluiría la versión real de HAL. Al nombrar el binario de esta manera, los clientes 2.0 pueden recuperarlo directamente y los clientes 2.1 pueden actualizar la implementación.

Luego, complete los stubs con funcionalidad y configure un demonio. Ejemplo de código de demonio (compatible con el paso a través):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementation dlopen() la biblioteca -impl proporcionada y la proporcionará como un servicio enlazado. Ejemplo de código de demonio (para servicio enlazado 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 will never exceed
    // 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 demonio generalmente vive en $PACKAGE + "-service-suffix" (por ejemplo, android.hardware.nfc@1.0-service ), pero podría estar en cualquier lugar. La política de seguridad para una clase específica de HAL es el atributo hal_<module> (por ejemplo, hal_nfc) . Este atributo se debe aplicar al demonio que ejecuta una HAL en particular (si el mismo proceso sirve para múltiples HAL, se pueden aplicar múltiples atributos).