Sie müssen alle Build-Flags, die für die bedingte Kompilierung des Frameworks verwendet werden, mit HIDL beschreiben. Relevante Build-Flags müssen gruppiert und in einer einzigen .hal
-Datei enthalten sein. Die Verwendung von HIDL zur Angabe von Konfigurationselementen bietet folgende Vorteile:
- Versioniert (um neue Konfigurationselemente hinzuzufügen, müssen Anbieter/OEMs die HAL explizit erweitern)
- Gut dokumentiert
- Zugriffssteuerung mit SELinux
- Gültigkeitsprüfung für Konfigurationselemente über die Vendor Test Suite (Bereichsprüfung, Prüfung der Abhängigkeiten zwischen Elementen usw.)
- Automatisch generierte APIs in C++ und Java
Build-Flags identifizieren, die vom Framework verwendet werden
Ermitteln Sie zuerst die Build-Konfigurationen, die zur bedingten Kompilierung des Frameworks verwendet werden, und verwerfen Sie dann veraltete Konfigurationen, um den Satz zu verkleinern. Für surfaceflinger
werden beispielsweise die folgenden Build-Flags identifiziert:
TARGET_USES_HWC2
TARGET_BOARD_PLATFORM
TARGET_DISABLE_TRIPLE_BUFFERING
TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
NUM_FRAMEBUFFER_SURFACE_BUFFERS
TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
VSYNC_EVENT_PHASE_OFFSET_NS
SF_VSYNC_EVENT_PHASE_OFFSET_NS
PRESENT_TIME_OFFSET_FROM_VSYNC_NS
MAX_VIRTUAL_DISPLAY_DIMENSION
HAL-Schnittstelle erstellen
Auf Build-Konfigurationen für ein Subsystem wird über eine HAL-Schnittstelle zugegriffen, während Schnittstellen zum Angeben von Konfigurationswerten im HAL-Paket android.hardware.configstore
(aktuell Version 1.0) gruppiert sind.
So erstellen Sie beispielsweise eine HAL-Schnittstellendatei für surfaceflinger
in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
:
package android.hardware.configstore@1.0; interface ISurfaceFlingerConfigs { // TO-BE-FILLED-BELOW };
Führen Sie nach dem Erstellen der Datei .hal
den Befehl hardware/interfaces/update-makefiles.sh
aus, um die neue Datei .hal
den Dateien Android.bp
und Android.mk
hinzuzufügen.
Funktionen für Build-Flags hinzufügen
Fügen Sie der Benutzeroberfläche für jede Build-Flag eine neue Funktion hinzu. Beispielsweise in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
:
interface ISurfaceFlingerConfigs { disableTripleBuffering() generates(OptionalBool ret); forceHwcForVirtualDisplays() generates(OptionalBool ret); enum NumBuffers: uint8_t { USE_DEFAULT = 0, TWO = 2, THREE = 3, }; numFramebufferSurfaceBuffers() generates(NumBuffers ret); runWithoutSyncFramework() generates(OptionalBool ret); vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret); presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret); maxVirtualDisplayDimension() generates(OptionalInt32 ret); };
Beim Hinzufügen einer Funktion:
- Verwenden Sie kurze Namen. Konvertieren Sie keine Namen von Makefile-Variablen in Funktionsnamen und denken Sie daran, dass die Präfixe
TARGET_
undBOARD_
nicht mehr erforderlich sind. - Kommentare hinzufügen Hilf den Entwicklern zu verstehen, welchen Zweck das Konfigurationselement hat, wie es das Framework-Verhalten ändert, welche Werte zulässig sind und welche anderen relevanten Informationen es gibt.
Rückgabetypen von Funktionen können Optional[Bool|String|Int32|UInt32|Int64|UInt64]
sein. Typen werden im selben Verzeichnis in types.hal
definiert und primitive Werte werden in einem Feld verpackt, das angibt, ob der Wert von der HAL angegeben ist. Andernfalls wird der Standardwert verwendet.
struct OptionalString { bool specified; string value; };
Definieren Sie gegebenenfalls das Enum, das den Typ des Konfigurationselements am besten darstellt, und verwenden Sie dieses Enum als Rückgabetyp. Im obigen Beispiel ist die Enum NumBuffers
definiert, um die Anzahl der gültigen Werte zu begrenzen. Fügen Sie beim Definieren solcher benutzerdefinierten Datentypen ein Feld oder einen Enumerationswert (z. B. USE_DEFAULT
) hinzu, um anzugeben, ob der Wert von der HAL angegeben wird oder nicht.
Es ist nicht zwingend erforderlich, dass ein einzelnes Build-Flag zu einer einzelnen Funktion in HIDL wird. Modulinhaber können alternativ eng miteinander verbundene Build-Flags in einem Strukturtyp zusammenfassen und eine Funktion haben, die diesen Strukturtyp zurückgibt. Dadurch kann die Anzahl der Funktionsaufrufe reduziert werden.
Eine Option zum Aggregieren von zwei Build-Flags zu einer einzigen Struktur in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
ist beispielsweise:
interface ISurfaceFlingerConfigs { // other functions here struct SyncConfigs { OptionalInt64 vsyncEventPhaseoffsetNs; OptionalInt64 presentTimeoffsetFromSyncNs; }; getSyncConfigs() generates (SyncConfigs ret); // other functions here };
Alternativen zu einer einzelnen HAL-Funktion
Als Alternative zur Verwendung einer einzigen HAL-Funktion für alle Build-Flags bietet die HAL-Oberfläche auch einfache Funktionen wie getBoolean(string
key)
und getInteger(string key)
. Die tatsächlichen key=value
-Paare werden in separaten Dateien gespeichert und der HAL-Dienst stellt Werte bereit, indem er diese Dateien liest/parst.
Dieser Ansatz ist zwar einfach zu definieren, bietet aber nicht die Vorteile von HIDL (erzwungene Versionierung, einfache Dokumentation, Zugriffssteuerung) und wird daher nicht empfohlen.
Einzelne und mehrere Schnittstellen
Für das Design der HAL-Schnittstelle für Konfigurationselemente gibt es zwei Auswahlmöglichkeiten:
- Eine Schnittstelle, die alle Konfigurationselemente abdeckt
- Mehrere Oberflächen, von denen jede eine Reihe zugehöriger Konfigurationselemente abdeckt
Eine einzelne Schnittstelle ist einfacher, kann jedoch unhandlich werden, da der einzelnen Datei weitere Konfigurationselemente hinzugefügt werden. Außerdem ist die Zugriffssteuerung nicht detailliert. Ein Prozess, dem Zugriff auf die Benutzeroberfläche gewährt wurde, kann also alle Konfigurationselemente lesen. Der Zugriff auf einen Teil der Konfigurationselemente kann nicht gewährt werden. Alternativ können Konfigurationselemente nicht gelesen werden, wenn der Zugriff nicht gewährt wird.
Aus diesen Gründen verwendet Android mehrere Schnittstellen mit einer einzigen HAL-Schnittstelle für eine Gruppe ähnlicher Konfigurationselemente. Beispiel: ISurfaceflingerConfigs
für surfaceflinger
-bezogene Konfigurationselemente und IBluetoothConfigs
für Bluetooth-bezogene Konfigurationselemente.