Cómo crear la interfaz de HAL

Debes usar el HIDL para describir todas las marcas de compilación que se usan para compilando el framework. Las marcas de compilación relevantes se deben agrupar y, además, incluir en un solo archivo .hal. Cómo usar HIDL para especificar elementos de configuración incluye los siguientes beneficios:

  • Con control de versiones (para agregar nuevos elementos de configuración, los proveedores o OEM deben extender explícitamente HAL)
  • Bien documentados
  • Control de acceso con SELinux
  • La comprobación de estado de los elementos de configuración mediante Prueba de proveedor Paquete (verificación de rango, verificación de dependencia entre elementos, etcétera)
  • APIs generadas de forma automática en C++ y Java

Cómo identificar las marcas de compilación que usa el framework

Comienza por identificar las configuraciones de compilación utilizadas para compilar de forma condicional la y luego abandonarás las configuraciones obsoletas para reducir el conjunto. Por ejemplo: el siguiente conjunto de marcas de compilación se identifica para 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

Cómo crear una interfaz de HAL

Se accede a los parámetros de configuración de compilación de un subsistema a través de una interfaz HAL, mientras que Las interfaces para dar valores de configuración se agrupan en el paquete HAL. android.hardware.configstore (actualmente en la versión 1.0) Por ejemplo, para crear un archivo de interfaz de HAL para surfaceflinger, en hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal

package android.hardware.configstore@1.0;

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

Después de crear el archivo .hal, ejecuta hardware/interfaces/update-makefiles.sh para agregar la nueva .hal a la Android.bp y Android.mk.

Cómo agregar funciones para marcas de compilación

Para cada marca de compilación, agrega una nueva función a la interfaz. Por ejemplo, en 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);
};

Cuando agregas una función:

  • Usa los nombres de manera concisa. Evita convertir variables en un archivo Make nombres en nombres de funciones. Ten en cuenta que TARGET_ y Los prefijos BOARD_ ya no son necesarios.
  • Agrega comentarios. Ayudar a los desarrolladores a comprender el propósito de la elemento de configuración, cómo cambia el comportamiento del framework, los valores válidos y otros elementos información.

Los tipos de datos que se devuelven de funciones Optional[Bool|String|Int32|UInt32|Int64|UInt64] Los tipos se definen en types.hal en el mismo directorio y unir los valores primitivos con un campo que indica si la HAL especifica el valor; De lo contrario, el valor predeterminado de salida.

struct OptionalString {
    bool specified;
    string value;
};

Cuando corresponda, define el tipo enum que mejor represente el tipo de de configuración y usar esa enumeración como el tipo de datos que se devuelve. En el ejemplo anterior, se define la enum NumBuffers para limitar la cantidad de salida. Cuando definas estos tipos de datos personalizados, agrega un campo o un valor de enumeración (para ejemplo, USE_DEFAULT) para indicar si el valor está o no está especificado por el HAL.

No es obligatorio que una sola marca de compilación se convierta en una sola función en HIDL De forma alternativa, los propietarios de módulos pueden agregar marcas de compilación estrechamente relacionadas en un struct y tienes una función que lo devuelve (si lo haces, puedes reducir la cantidad de llamadas a funciones).

Por ejemplo, una opción para agregar dos marcas de compilación en un solo struct en hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal es:

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

Alternativas a una sola función de HAL

Como alternativa al uso de una sola función de HAL para todas las marcas de compilación, la HAL también proporciona funciones simples como getBoolean(string key) y getInteger(string key). El estado Los pares de key=value se almacenan en archivos separados y en el servicio de HAL. proporciona valores leyendo y analizando esos archivos.

Si bien este enfoque es fácil de definir, no incluye los beneficios proporcionados por HIDL (control de versiones aplicado, facilidad de documentación, control de acceso) por lo que no se recomienda.

Interfaces únicas y múltiples

El diseño de la interfaz de HAL para elementos de configuración presenta dos opciones:

  • Una sola interfaz que abarca todos los elementos de configuración
  • Varias interfaces, cada una de las cuales abarca un conjunto de parámetros de configuración relacionados elementos

Una sola interfaz es más fácil, pero puede volverse insostenible a medida que aumenta los elementos de configuración se agregan al único archivo. Además, el control de acceso no es detallado, por lo que un proceso al que se le otorga acceso a la interfaz puede leer todos los elementos de configuración (no se puede otorgar acceso a un conjunto parcial de elementos otorgada). Como alternativa, si no se otorga acceso, los elementos de configuración no pueden leer.

Debido a estos problemas, Android usa interfaces múltiples con una sola HAL. de un grupo de elementos de configuración relacionados. Por ejemplo: ISurfaceflingerConfigs para surfaceflinger y IBluetoothConfigs para elementos relacionados con Bluetooth elementos de configuración.