Dynamisch verfügbare HALs

Android 9 unterstützt das dynamische Herunterfahren von Android-Hardware-Subsystemen, wenn diese nicht verwendet oder nicht benötigt werden. Wenn ein Benutzer beispielsweise kein WLAN nutzt, sollten die WLAN-Subsysteme keinen Speicher, Strom oder andere Systemressourcen beanspruchen. In früheren Android-Versionen blieben HALs/Treiber auf Android-Geräten während der gesamten Bootzeit eines Android-Telefons geöffnet.

Die Implementierung des dynamischen Herunterfahrens umfasst die Verkabelung von Datenflüssen und die Ausführung dynamischer Prozesse, wie in den folgenden Abschnitten beschrieben.

Änderungen an HAL-Definitionen

Für das dynamische Herunterfahren sind Informationen darüber erforderlich, welche Prozesse welche HAL-Schnittstellen bedienen (diese Informationen können später auch in anderen Kontexten nützlich sein) und es dürfen keine Prozesse beim Booten gestartet und beim Beenden nicht neu gestartet werden (bis eine erneute Aufforderung erfolgt).

# 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

Änderungen an init und hwservicemanager

Beim dynamischen Herunterfahren muss der hwservicemanager init außerdem anweisen, die angeforderten Dienste zu starten. In Android 9 enthält init drei zusätzliche Steuernachrichten (z. B. ctl.start ): ctl.interface_start , ctl.interface_stop und ctl.interface_restart . Diese Nachrichten können verwendet werden, um init zu signalisieren, bestimmte Hardwareschnittstellen hoch- und herunterzufahren. Wenn ein Dienst angefordert und nicht registriert ist, fordert hwservicemanager den Start des Dienstes an. Dynamische HALs erfordern jedoch keines davon.

Bestimmen Sie den HAL-Ausgang

In Android 9 muss der HAL-Exit manuell festgelegt werden. Für Android 10 und höher kann es auch mit automatischen Lebenszyklen ermittelt werden.

Beim dynamischen Herunterfahren sind mehrere Richtlinien erforderlich, um zu entscheiden, wann ein HAL gestartet und wann ein HAL heruntergefahren werden soll. Wenn sich ein HAL aus irgendeinem Grund zum Beenden entscheidet, wird er automatisch neu gestartet, wenn er erneut benötigt wird. Dabei werden die in der HAL-Definition bereitgestellten Informationen und die durch Änderungen an init und hwservicemanager bereitgestellte Infrastruktur verwendet. Dies könnte verschiedene Strategien beinhalten, darunter:

  • Ein HAL könnte sich dafür entscheiden, „exit“ für sich selbst aufzurufen, wenn jemand eine „close“-API oder eine ähnliche API dafür aufruft. Dieses Verhalten muss in der entsprechenden HAL-Schnittstelle angegeben werden.
  • HALs können heruntergefahren werden, wenn ihre Aufgabe abgeschlossen ist (dokumentiert in der HAL-Datei).

Automatische Lebenszyklen

Android 10 bietet mehr Unterstützung für den Kernel und hwservicemanager , was es HALs ermöglicht, automatisch herunterzufahren, wenn sie keine Clients haben. Um diese Funktion zu verwenden, führen Sie alle Schritte unter „Änderungen an HAL-Definitionen“ aus und gehen außerdem wie folgt vor:

  • Registrieren Sie den Dienst in C++ mit LazyServiceRegistrar anstelle der Mitgliedsfunktion registerAsService , zum Beispiel:
    // only one instance of LazyServiceRegistrar per process
    LazyServiceRegistrar registrar;
    registrar.registerAsService(myHidlService /* , "default" */);
  • Stellen Sie sicher, dass der HAL-Client nur dann einen Verweis auf die HAL der obersten Ebene (die bei hwservicemanager registrierte Schnittstelle) beibehält, wenn diese verwendet wird. Um Verzögerungen zu vermeiden, wenn diese Referenz in einem Hwbinder-Thread gelöscht wird, der weiterhin ausgeführt wird, sollte der Client nach dem Löschen der Referenz auch IPCThreadState::self()->flushCommands() aufrufen, um sicherzustellen, dass der Binder-Treiber über den zugehörigen Referenzzähler benachrichtigt wird Änderungen.