HIDL C++

Android 8 redéfinit l'architecture du système d'exploitation Android afin de définir des interfaces claires entre les plate-forme Android indépendante de l'appareil et 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éfini comme des en-têtes C dans hardware/libhardware. HIDL les remplace Les interfaces HAL ont des interfaces stables avec versions gérées, qui peuvent être interfaces HIDL côté serveur en C++ (décrites 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 du .hal HIDL par le compilateur hidl-gen, la manière dont ils 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 le 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 vers des HAL HIDL, le HAL l'implémentation devient le serveur, et le processus appelant le HAL devient le client. Les implémentations par défaut peuvent être diffusées à la fois en mode passthrough et en liaison et peuvent évoluer au fil du temps:

Figure 1 : Progression du développement des anciennes HAL.

Créer le client HAL

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

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

Incluez ensuite 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éer le serveur HAL

Pour créer l'implémentation HAL, vous devez disposer des fichiers .hal qui représentent votre HAL et qui ont déjà généré des fichiers makefile pour votre HAL à l'aide de -Lmakefile ou -Landroidbp sur hidl-gen (./hardware/interfaces/update-makefiles.sh pour les requêtes internes fichiers HAL et constitue une référence utile). Lorsque vous transférez des HAL depuis libhardware, vous pouvez effectuer une grande partie de ces tâches facilement à l'aide de c2hal.

Pour créer les fichiers nécessaires à l'implémentation de votre HAL, procédez comme suit:

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 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 le passthrough la mise en œuvre. Les conditions requises pour le mode passthrough sont remplies automatiquement ci-dessus, qui créent également le 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 dans un binaire appelé android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER) En général, le OPTIONAL_IDENTIFIER inclut ici le code HAL réel version. En nommant le binaire comme ceci, les clients 2.0 peuvent le récupérer directement, et les clients 2.1 peuvent upcaster l'implémentation.

Remplissez ensuite les bouchons avec des fonctionnalités et configurez un daemon. Exemple code daemon (compatible avec le passthrough):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementation appels dlopen() pour la bibliothèque -impl fournie et la fournit en tant que un service lié. Exemple de code daemon (pour un service lié uniquement):

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
}

Ce daemon se trouve généralement dans $PACKAGE + "-service-suffix" (pour par exemple android.hardware.nfc@1.0-service), mais il peut se trouver n'importe où. La règle sepolicy appliquée à un élément classe des HAL est l'attribut hal_<module> (par exemple, hal_nfc) Cet attribut doit être appliqué au daemon qui exécute une HAL spécifique (si le même processus traite plusieurs HAL, plusieurs attributs peuvent lui être appliquées).