HAL disponibles dynamiquement

Android 9 est compatible avec l'arrêt dynamique des sous-systèmes matériels Android lorsqu'ils ne sont pas utilisés ou pas nécessaires. Par exemple, lorsqu'un utilisateur n'utilise pas le Wi-Fi, les sous-systèmes Wi-Fi ne doivent pas utiliser de mémoire, d'énergie ni d'autres ressources système. Dans les versions précédentes d'Android, les HAL/pilotes étaient maintenus ouverts sur les appareils Android pendant toute la durée du démarrage d'un téléphone Android.

L'implémentation d'un arrêt dynamique implique de connecter les flux de données et d'exécuter des processus dynamiques, comme indiqué dans les sections suivantes.

Modifications apportées aux définitions HAL

L'arrêt dynamique nécessite des informations sur les processus qui servent les interfaces HAL (ces informations peuvent également être utiles plus tard dans d'autres contextes), ainsi que de ne pas démarrer les processus au démarrage et de ne pas les redémarrer (jusqu'à ce qu'ils soient à nouveau demandés) lorsqu'ils se terminent.

# some init.rc script associated with the HAL
service vendor.some-service-name /vendor/bin/hw/some-binary-service
    # init language extension, provides information of what service is served
    # if multiple interfaces are served, they can be specified one on each line
    interface android.hardware.light@2.0::ILight default
    # restarted if hwservicemanager dies
    # would also cause the hal to start early during boot if disabled wasn't set
    class hal
    # will not be restarted if it exits until it is requested to be restarted
    oneshot
    # will only be started when requested
    disabled
    # ... other properties

Modifications apportées à init et hwservicemanager

L'arrêt dynamique nécessite également que hwservicemanager indique à init de démarrer les services demandés. Dans Android 9, init inclut trois messages de contrôle supplémentaires (par exemple, ctl.start): ctl.interface_start, ctl.interface_stop et ctl.interface_restart. Ces messages peuvent être utilisés pour indiquer à init d'activer et de désactiver des interfaces matérielles spécifiques. Lorsqu'un service est demandé et qu'il n'est pas enregistré, hwservicemanager demande que le service soit démarré. Toutefois, les HAL dynamiques ne nécessitent aucune de ces méthodes.

Déterminer la sortie de la HAL

Sous Android 9, la sortie HAL doit être déterminée manuellement. Pour Android 10 et versions ultérieures, cela peut également être déterminé avec des cycles de vie automatiques.

L'arrêt dynamique nécessite plusieurs règles pour décider quand démarrer un HAL et quand l'arrêter. Si un HAL décide de se fermer pour une raison quelconque, il sera automatiquement redémarré lorsqu'il sera à nouveau nécessaire à l'aide des informations fournies dans la définition du HAL et de l'infrastructure fournie par les modifications apportées à init et hwservicemanager. Vous pouvez utiliser plusieurs stratégies différentes, y compris les suivantes:

  • Un HAL peut choisir d'appeler la sortie sur lui-même si quelqu'un appelle une API de fermeture ou similaire. Ce comportement doit être spécifié dans l'interface HAL correspondante.
  • Les HAL peuvent s'arrêter une fois leur tâche terminée (documentée dans le fichier HAL).

Cycles de vie automatiques

Android 10 ajoute une compatibilité accrue au kernel et à hwservicemanager, ce qui permet aux HAL de s'arrêter automatiquement lorsqu'ils n'ont pas de clients. Pour utiliser cette fonctionnalité, suivez toutes les étapes de la section Modifications apportées aux définitions HAL, ainsi que les étapes suivantes:

  • Enregistrez le service en C++ avec LazyServiceRegistrar au lieu de la fonction membre registerAsService, par exemple:
    // only one instance of LazyServiceRegistrar per process
    LazyServiceRegistrar registrar;
    registrar.registerAsService(myHidlService /* , "default" */);
  • Vérifiez que le client HAL ne conserve une référence au HAL de niveau supérieur (l'interface enregistrée avec hwservicemanager) que lorsqu'il est utilisé. Pour éviter les retards si cette référence est supprimée sur un thread hwbinder qui continue de s'exécuter, le client doit également appeler IPCThreadState::self()->flushCommands() après avoir supprimé la référence pour s'assurer que le pilote du liaisonneur est informé des modifications du nombre de références associées.