Création de l'interface HAL

Vous devez utiliser HIDL pour décrire tous les indicateurs de build utilisés pour la compilation conditionnelle du framework. Les indicateurs de build pertinents doivent être regroupés et inclus dans un seul fichier .hal . L'utilisation de HIDL pour spécifier des éléments de configuration présente les avantages suivants :

  • Versionné (pour ajouter de nouveaux éléments de configuration, les fournisseurs/OEM doivent explicitement étendre le HAL)
  • Bien documenté
  • Contrôle d'accès à l'aide de SELinux
  • Vérification de l'intégrité des éléments de configuration via Vendor Test Suite (vérification de plage, vérification d'interdépendance entre les éléments, etc.)
  • API générées automatiquement en C++ et Java

Identifier les indicateurs de build utilisés par le framework

Commencez par identifier les configurations de build utilisées pour compiler le framework de manière conditionnelle, puis abandonnez les configurations obsolètes pour réduire la taille de l'ensemble. Par exemple, l'ensemble d'indicateurs de build suivant est identifié pour surfaceflinger :

  • 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

Création d'une interface HAL

Les configurations de construction pour un sous-système sont accessibles via une interface HAL, tandis que les interfaces permettant de donner des valeurs de configuration sont regroupées dans le package HAL android.hardware.configstore (actuellement en version 1.0). Par exemple, pour créer un fichier d'interface HAL pour surfaceflinger , dans hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal :

package android.hardware.configstore@1.0;

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

Après avoir créé le fichier .hal , exécutez hardware/interfaces/update-makefiles.sh pour ajouter le nouveau fichier .hal aux fichiers Android.bp et Android.mk .

Ajout de fonctions pour les indicateurs de build

Pour chaque indicateur de build, ajoutez une nouvelle fonction à l'interface. Par exemple, dans 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);
};

Lors de l'ajout d'une fonction :

  • Soyez concis avec les noms. Évitez de convertir les noms de variables makefile en noms de fonctions et gardez à l'esprit que les préfixes TARGET_ et BOARD_ ne sont plus nécessaires.
  • Ajoutez des commentaires. Aidez les développeurs à comprendre l'objectif de l'élément de configuration, comment il modifie le comportement du framework, les valeurs valides et d'autres informations pertinentes.

Les types de retour de fonction peuvent être Optional[Bool|String|Int32|UInt32|Int64|UInt64] . Les types sont définis dans types.hal dans le même répertoire et enveloppent les valeurs primitives avec un champ qui indique si la valeur est spécifiée par HAL ; sinon, la valeur par défaut est utilisée.

struct OptionalString {
    bool specified;
    string value;
};

Le cas échéant, définissez l’énumération qui représente le mieux le type de l’élément de configuration et utilisez cette énumération comme type de retour. Dans l'exemple ci-dessus, l'énumération NumBuffers est définie pour limiter le nombre de valeurs valides. Lors de la définition de tels types de données personnalisés, ajoutez un champ ou une valeur d'énumération (par exemple, USE_DEFAULT ) pour indiquer si la valeur est/n'est pas spécifiée par la HAL.

Il n'est pas obligatoire qu'un seul indicateur de build devienne une seule fonction dans HIDL. Les propriétaires de modules peuvent également regrouper des indicateurs de construction étroitement liés dans une structure et disposer d'une fonction qui renvoie cette structure (cela peut réduire le nombre d'appels de fonction).

Par exemple, une option pour agréger deux indicateurs de build en une seule structure dans hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal est :

 interface ISurfaceFlingerConfigs {
    // other functions here
    struct SyncConfigs {
        OptionalInt64 vsyncEventPhaseoffsetNs;
        OptionalInt64 presentTimeoffsetFromSyncNs;
    };
    getSyncConfigs() generates (SyncConfigs ret);
    // other functions here
};

Alternatives à une seule fonction HAL

Au lieu d'utiliser une seule fonction HAL pour tous les indicateurs de build, l'interface HAL fournit également des fonctions simples telles que getBoolean(string key) et getInteger(string key) . Les paires key=value réelles sont stockées dans des fichiers séparés et le service HAL fournit des valeurs en lisant/analysant ces fichiers.

Bien que cette approche soit facile à définir, elle n'inclut pas les avantages apportés par HIDL (version renforcée, facilité de documentation, contrôle d'accès) et n'est donc pas recommandée.

Interfaces simples et multiples

La conception de l'interface HAL pour les éléments de configuration présente deux choix :

  • Une interface unique qui couvre tous les éléments de configuration
  • Plusieurs interfaces, chacune couvrant un ensemble d'éléments de configuration associés

Une interface unique est plus simple mais peut devenir impossible à maintenir à mesure que davantage d'éléments de configuration sont ajoutés au fichier unique. De plus, le contrôle d'accès n'est pas précis, donc un processus qui a accès à l'interface peut lire tous les éléments de configuration (l'accès à un ensemble partiel d'éléments de configuration ne peut pas être accordé). Alternativement, si l'accès n'est pas accordé, les éléments de configuration ne peuvent pas être lus.

En raison de ces problèmes, Android utilise plusieurs interfaces avec une seule interface HAL pour un groupe d'éléments de configuration associés. Par exemple, ISurfaceflingerConfigs pour les éléments de configuration liés surfaceflinger et IBluetoothConfigs pour les éléments de configuration liés à Bluetooth.