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 zur Angabe 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, Prüfung der Abhängigkeiten zwischen Elementen usw.)
  • Automatisch generierte APIs in C++ und Java

Identifizieren der vom Framework verwendeten Build-Flags

Identifizieren Sie zunächst die Build-Konfigurationen, die zum bedingten Kompilieren des Frameworks verwendet werden, und verzichten Sie dann auf veraltete Konfigurationen, um den Satz zu verkleinern. Beispielsweise werden die folgenden 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 zur Angabe von Konfigurationswerten im HAL-Paket android.hardware.configstore (derzeit Version 1.0) gruppiert sind. Um beispielsweise eine HAL-Schnittstellendatei für surfaceflinger zu erstellen, gehen Sie 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 .hal Datei hardware/interfaces/update-makefiles.sh aus, um die neue .hal Datei zu den Dateien Android.bp und Android.mk hinzuzufügen.

Funktionen für Build-Flags hinzufügen

Fügen Sie für jedes Build-Flag eine neue Funktion zur Schnittstelle 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 bei Namen. Vermeiden Sie die Konvertierung von Makefile-Variablennamen in Funktionsnamen und bedenken Sie, 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 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 durch die 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 darstellt, und verwenden Sie diese Aufzählung als Rückgabetyp. Im obigen Beispiel ist die NumBuffers Enumeration definiert, um die Anzahl gültiger 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 durch die 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 über eine Funktion verfügen, die diese Struktur zurückgibt (dadurch kann die Anzahl der Funktionsaufrufe reduziert werden).

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 eigentlichen key=value Paare werden in separaten Dateien gespeichert und der HAL-Dienst stellt Werte durch Lesen/Parsen dieser Dateien bereit.

Obwohl dieser Ansatz einfach zu definieren ist, umfasst 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 nicht mehr wartbar sein, wenn der einzelnen Datei weitere Konfigurationselemente hinzugefügt werden. Darüber hinaus ist die Zugriffskontrolle nicht differenziert, sodass ein Prozess, dem Zugriff auf die Schnittstelle gewährt wird, alle Konfigurationselemente lesen kann (der 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. Beispielsweise ISurfaceflingerConfigs für surfaceflinger -bezogene Konfigurationselemente und IBluetoothConfigs für Bluetooth-bezogene Konfigurationselemente.