HAL disponibles dynamiquement

Android 9 prend en charge l'arrêt dynamique des sous-systèmes matériels Android lorsqu'ils ne sont pas utilisés ou inutiles. 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 ou d'autres ressources système. Dans les versions antérieures d'Android, les HAL/pilotes restaient ouverts sur les appareils Android pendant toute la durée du démarrage du téléphone Android.

La mise en œuvre d'un arrêt dynamique implique le câblage des flux de données et l'exécution de processus dynamiques, comme détaillé dans les sections suivantes.

Modifications des définitions HAL

L'arrêt dynamique nécessite des informations sur les processus qui servent quelles interfaces HAL (ces informations peuvent également être utiles ultérieurement dans d'autres contextes), ainsi que le fait 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) à leur sortie.

# 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 signaler init d'activer et de désactiver des interfaces matérielles spécifiques. Lorsqu'un service est demandé et n'est pas enregistré, hwservicemanager demande que le service soit démarré. Cependant, les HAL dynamiques ne nécessitent l’utilisation d’aucun de ces éléments.

Déterminer la sortie de 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 politiques pour décider quand démarrer et arrêter une HAL. Si un HAL décide de se fermer pour une raison quelconque, il sera automatiquement redémarré lorsqu'il sera à nouveau nécessaire en utilisant les informations fournies dans la définition de HAL et l'infrastructure fournie par les modifications apportées à init et hwservicemanager . Cela pourrait impliquer plusieurs stratégies différentes, notamment :

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

Cycles de vie automatiques

Android 10 ajoute davantage de prise en charge au noyau et hwservicemanager , ce qui permet aux HAL de s'arrêter automatiquement lorsqu'ils n'ont aucun client. Pour utiliser cette fonctionnalité, effectuez toutes les étapes décrites dans Modifications des définitions HAL ainsi que :

  • 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 conserve une référence au HAL de niveau supérieur (l'interface enregistrée avec hwservicemanager ) uniquement 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 garantir que le pilote du classeur est informé du nombre de références associé. changements.