HAL-Schnittstelle erstellen

Sie müssen HIDL verwenden, um alle Build-Flags zu beschreiben, die für die bedingte Kompilierung des Frameworks verwendet werden. Relevante Build-Flags müssen gruppiert und in einer einzelnen .hal-Datei enthalten sein. Die Verwendung von HIDL zum Angeben von Konfigurationselementen bietet folgende Vorteile:

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

Vom Framework verwendete Build-Flags identifizieren

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

Build-Konfigurationen für ein Subsystem werden über eine HAL-Schnittstelle aufgerufen. Schnittstellen zum Bereitstellen von Konfigurationswerten sind im HAL-Paket android.hardware.configstore (derzeit in Version 1.0) gruppiert. 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
};

Nachdem Sie die Datei .hal erstellt haben, führen Sie 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 Schnittstelle für jedes Build-Flag eine neue Funktion hinzu. 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);
};

Wenn Sie eine Funktion hinzufügen:

  • Fassen Sie sich kurz. Vermeiden Sie die Umwandlung von Makefile-Variablennamen in Funktionsnamen und denken Sie daran, dass die Präfixe TARGET_ und BOARD_ nicht mehr erforderlich sind.
  • Kommentare hinzufügen Helfen Sie Entwicklern, den Zweck des Konfigurationselements zu verstehen und zu verstehen, wie es das Framework-Verhalten, gültige Werte und andere relevante Informationen ändert.

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

struct OptionalString {
    bool specified;
    string value;
};

Definieren Sie gegebenenfalls die Aufzählung, die den Typ des Konfigurationselements am besten repräsentiert, und verwenden Sie diese Aufzählung 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 benutzerdefinierter Datentypen ein Feld oder einen Aufzählungswert (z. B. USE_DEFAULT) hinzu, um anzugeben, ob der Wert durch den HAL angegeben wird oder nicht.

Ein einzelnes Build-Flag muss in HIDL nicht zu einer einzelnen Funktion werden. Modulinhaber können alternativ eng verwandte Build-Flags in einer Struktur aggregieren und eine Funktion haben, die diese Struktur 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 durch Lesen/Parsen dieser Dateien bereit.

Dieser Ansatz ist zwar leicht zu definieren, bietet jedoch nicht die Vorteile von HIDL (erzwungene Versionsverwaltung, einfache Dokumentation, Zugriffssteuerung) und wird daher nicht empfohlen.

Eine und mehrere Benutzeroberflächen

Für das Design der HAL-Schnittstelle für Konfigurationselemente gibt es zwei Auswahlmöglichkeiten:

  • Eine Schnittstelle, die alle Konfigurationselemente abdeckt
  • Mehrere Schnittstellen, die jeweils eine Reihe verwandter Konfigurationselemente abdecken

Eine einzelne Schnittstelle ist einfacher, kann jedoch unhandlich werden, da der einzelnen Datei weitere Konfigurationselemente hinzugefügt werden. Darüber hinaus ist die Zugriffssteuerung nicht detailliert, sodass ein Prozess, dem Zugriff auf die Schnittstelle gewährt wird, alle Konfigurationselemente lesen kann (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.

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