Erstellen der HAL-Schnittstelle

Sie müssen HIDL verwenden, um alle Build-Flags zu beschreiben, die zum bedingten Kompilieren des Frameworks verwendet werden. Relevante Build-Flags müssen gruppiert und in einer einzigen .hal -Datei enthalten sein. Die Verwendung von HIDL zum Angeben von Konfigurationselementen bietet die folgenden Vorteile:

  • Versioniert (um neue Konfigurationselemente hinzuzufügen, müssen Anbieter/OEMs die HAL explizit erweitern)
  • Gut dokumentiert
  • Zugriffskontrolle mit SELinux
  • Plausibilitätsprüfung für Konfigurationselemente durch die Vendor Test Suite (Bereichsprüfung, Abhängigkeitsprüfung zwischen Elementen usw.)
  • Automatisch generierte APIs in C++ und Java

Identifizieren von Build-Flags, die vom Framework verwendet werden

Beginnen Sie damit, die Build-Konfigurationen zu identifizieren, die zum bedingten Kompilieren des Frameworks verwendet werden, und verwerfen Sie dann veraltete Konfigurationen, um den Satz kleiner zu machen. Beispielsweise wird der folgende Satz von Build-Flags für surfaceflinger 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

Erstellen einer HAL-Schnittstelle

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 (derzeit in Version 1.0) gruppiert sind. Um beispielsweise eine HAL-Schnittstellendatei für surfaceflinger in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal zu erstellen:

package android.hardware.configstore@1.0;

interface ISurfaceFlingerConfigs {
    // TO-BE-FILLED-BELOW
};

Führen Sie nach dem Erstellen der .hal -Datei hardware/interfaces/update-makefiles.sh aus, um die neue .hal -Datei zu den Dateien Android.bp und Android.mk .

Hinzufügen von Funktionen für Build-Flags

Fügen Sie der Schnittstelle für jedes Build-Flag eine neue Funktion hinzu. Zum Beispiel 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:

  • Seien Sie prägnant mit Namen. Vermeiden Sie es, Makefile-Variablennamen in Funktionsnamen umzuwandeln, und denken Sie daran, dass die Präfixe TARGET_ und BOARD_ nicht mehr erforderlich sind.
  • Füge Kommentare hinzu. Helfen Sie Entwicklern, den Zweck des Konfigurationselements zu verstehen, wie es das Frameworkverhalten, gültige Werte und andere relevante Informationen ändert.

Funktionsrückgabetypen können Optional[Bool|String|Int32|UInt32|Int64|UInt64] . Typen werden in types.hal im selben Verzeichnis definiert und umschließen primitive Werte mit einem Feld, das angibt, ob der Wert von der HAL angegeben wird; wenn nicht, wird der Standardwert verwendet.

struct OptionalString {
    bool specified;
    string value;
};

Definieren Sie gegebenenfalls die Aufzählung, die den Typ des Konfigurationselements am besten darstellt, und verwenden Sie diese Aufzählung als Rückgabetyp. Im obigen Beispiel wird die Aufzählung NumBuffers definiert, um die Anzahl gültiger Werte zu begrenzen. Fügen Sie beim Definieren solcher benutzerdefinierten Datentypen ein Feld oder einen Aufzählungswert (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. Modulbesitzer können alternativ eng verwandte Build-Flags in einer Struktur zusammenfassen und eine Funktion haben, die diese Struktur zurückgibt (dies kann die Anzahl der Funktionsaufrufe reduzieren).

Eine Option zum Zusammenfassen von zwei Build-Flags in 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 einzelnen HAL-Funktion für alle Build-Flags bietet die HAL-Schnittstelle 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.

Obwohl dieser Ansatz einfach zu definieren ist, beinhaltet er nicht die Vorteile von HIDL (erzwungene Versionierung, einfache Dokumentation, Zugriffskontrolle) und wird daher nicht empfohlen.

Einzelne und mehrere Schnittstellen

Das Design der HAL-Schnittstelle für Konfigurationselemente bietet zwei Möglichkeiten:

  • Eine einzige Schnittstelle, die alle Konfigurationselemente abdeckt
  • Mehrere Schnittstellen, von denen jede eine Reihe verwandter Konfigurationselemente abdeckt

Eine einzelne Schnittstelle ist einfacher, kann jedoch unwartbar werden, wenn mehr Konfigurationselemente zu einer einzelnen Datei hinzugefügt werden. Darüber hinaus ist die Zugriffssteuerung nicht feinkörnig, sodass ein Prozess, dem Zugriff auf die Schnittstelle gewährt wurde, alle Konfigurationselemente lesen kann (Zugriff auf einen Teilsatz von Konfigurationselementen kann nicht gewährt werden). Alternativ können Konfigurationselemente nicht gelesen werden, wenn der Zugriff nicht gewährt wird.

Aufgrund dieser Probleme verwendet Android mehrere Schnittstellen mit einer einzigen HAL-Schnittstelle für eine Gruppe verwandter Konfigurationselemente. Zum Beispiel ISurfaceflingerConfigs für surfaceflinger -bezogene Konfigurationselemente und IBluetoothConfigs für Bluetooth-bezogene Konfigurationselemente.