HIDL C ++

Android O restructure le système d'exploitation Android pour définir des interfaces claires entre la plate-forme Android indépendante de l'appareil et le code spécifique à l'appareil et au fournisseur. Android définit déjà de nombreuses interfaces de ce type sous la forme d'interfaces HAL, définies comme des en-têtes C dans hardware/libhardware . HIDL remplace ces interfaces HAL par des interfaces stables et versionnées, qui peuvent être des interfaces HIDL côté client et serveur en C ++ (décrit ci-dessous) ou Java .

Les pages de cette section décrivent les implémentations C ++ des interfaces HIDL, y compris des détails sur les fichiers générés automatiquement à partir des fichiers HIDL .hal par le compilateur hidl-gen , comment ces fichiers sont empaquetés et comment intégrer ces fichiers avec le code C ++ qui les utilise.

Implémentations client et serveur

Les interfaces HIDL ont des implémentations client et serveur:

  • Un client d'une interface HIDL est le code qui utilise l'interface en appelant des méthodes dessus.
  • Un serveur est une implémentation d'une interface HIDL qui reçoit les appels des clients et renvoie les résultats (si nécessaire).

Lors de la transition des HAL libhardware HAL HIDL, l'implémentation HAL devient le serveur et le processus appelant dans le HAL devient le client. Les implémentations par défaut peuvent servir à la fois des HAL passthrough et binderized, et peuvent changer au fil du temps:

Figure 1. Progression du développement des HAL hérités.

Création du client HAL

Commencez par inclure les bibliothèques HAL dans le makefile:

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

Ensuite, incluez les fichiers d'en-tête HAL:

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

Création du serveur HAL

Pour créer l'implémentation HAL, vous devez avoir les fichiers .hal qui représentent votre HAL et avoir déjà généré des makefiles pour votre HAL en utilisant -Lmakefile ou -Landroidbp sur hidl-gen ( ./hardware/interfaces/update-makefiles.sh fait pour fichiers HAL internes et constitue une bonne référence). Lors du transfert via des HAL à partir de libhardware , vous pouvez effectuer une grande partie de ce travail facilement en utilisant c2hal.

Pour créer les fichiers nécessaires à l'implémentation de votre 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

Pour que le HAL fonctionne en mode passthrough, vous devez avoir la fonction HIDL_FETCH_IModuleName résidant dans /(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl( OPTIONAL_IDENTIFIER ).soOPTIONAL_IDENTIFIER est une chaîne identifiant l'implémentation de relais. Les exigences du mode passthrough sont remplies automatiquement par les commandes ci-dessus, qui créent également la cible android.hardware.nfc@1.0-impl , mais n'importe quelle extension peut être utilisée. Par exemple, android.hardware.nfc@1.0-impl-foo utilise -foo pour se différencier.

Si un HAL est une version mineure ou une extension d'un autre HAL, le HAL de base doit être utilisé pour nommer ce binaire. Par exemple, les implémentations android.hardware.graphics.mapper@2.1 doivent toujours être dans un binaire appelé android.hardware.graphics.mapper@2.0-impl( OPTIONAL_IDENTIFIER ) . Habituellement, le OPTIONAL_IDENTIFIER ici inclurait la version HAL réelle. En nommant le binaire comme ceci, les clients 2.0 peuvent le récupérer directement, et les clients 2.1 peuvent remonter l'implémentation.

Ensuite, remplissez les stubs avec des fonctionnalités et configurez un démon. Exemple de code de démon (prenant en charge le passthrough):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementation dlopen() la bibliothèque -impl fournie et la fournira en tant que service lié. Exemple de code démon (pour un service purement lié):

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
}

Ce démon vit généralement dans $PACKAGE + "-service-suffix" (par exemple, android.hardware.nfc@1.0-service ), mais il peut être n'importe où. La sepolicy pour une classe spécifique de HAL est l'attribut hal_<module> (par exemple, hal_nfc) . Cet attribut doit être appliqué au démon qui exécute une HAL particulière (si le même processus sert plusieurs HAL, plusieurs attributs peuvent lui être appliqués).