Creación de la interfaz HAL

Debe utilizar HIDL para describir todos los indicadores de compilación utilizados para compilar condicionalmente el marco. Las marcas de compilación relevantes deben agruparse e incluirse en un único archivo .hal . El uso de HIDL para especificar elementos de configuración incluye los siguientes beneficios:

  • Versionado (para agregar nuevos elementos de configuración, los proveedores/OEM deben extender explícitamente el HAL)
  • Bien documentada
  • Control de acceso mediante SELinux
  • Verificación de integridad de los elementos de configuración a través del Vendor Test Suite (verificación de rango, verificación de interdependencia entre elementos, etc.)
  • API generadas automáticamente tanto en C++ como en Java

Identificar los indicadores de compilación utilizados por el marco

Comience identificando las configuraciones de compilación utilizadas para compilar condicionalmente el marco, luego abandone las configuraciones obsoletas para hacer el conjunto más pequeño. Por ejemplo, se identifica el siguiente conjunto de indicadores de compilación 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

Creando una interfaz HAL

Se accede a las configuraciones de compilación para un subsistema a través de una interfaz HAL, mientras que las interfaces para proporcionar 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 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 , ejecute hardware/interfaces/update-makefiles.sh para agregar el nuevo archivo .hal a los archivos Android.bp y Android.mk .

Agregar funciones para banderas de compilación

Para cada indicador de compilación, agregue 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);
};

Al agregar una función:

  • Sea conciso con los nombres. Evite convertir nombres de variables de archivos MAKE en nombres de funciones y tenga en cuenta que los prefijos TARGET_ y BOARD_ ya no son necesarios.
  • Añadir comentarios. Ayude a los desarrolladores a comprender el propósito del elemento de configuración, cómo cambia el comportamiento del marco, los valores válidos y otra información relevante.

Los tipos de retorno de funciones pueden ser Optional[Bool|String|Int32|UInt32|Int64|UInt64] . Los tipos se definen en types.hal en el mismo directorio y envuelven los valores primitivos con un campo que indica si el valor está especificado por HAL; en caso contrario, se utiliza el valor predeterminado.

struct OptionalString {
    bool specified;
    string value;
};

Cuando sea apropiado, defina la enumeración que mejor represente el tipo de elemento de configuración y use esa enumeración como tipo de devolución. En el ejemplo anterior, la enumeración NumBuffers está definida para limitar el número de valores válidos. Al definir dichos tipos de datos personalizados, agregue un campo o un valor de enumeración (por ejemplo, USE_DEFAULT ) para indicar si el valor está o no especificado por HAL.

No es obligatorio que un único indicador de compilación se convierta en una única función en HIDL. Alternativamente, los propietarios de módulos pueden agregar indicadores de compilación estrechamente relacionados en una estructura y tener una función que devuelva esa estructura (al hacerlo, se puede reducir la cantidad de llamadas a funciones).

Por ejemplo, una opción para agregar dos indicadores de compilación en una sola estructura 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 única función HAL

Como alternativa al uso de una única función HAL para todos los indicadores de compilación, la interfaz HAL también proporciona funciones simples como getBoolean(string key) y getInteger(string key) . Los pares key=value reales se almacenan en archivos separados y el servicio HAL proporciona valores leyendo/analizando esos archivos.

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

Interfaces únicas y múltiples

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

  • Una única interfaz que cubre todos los elementos de configuración.
  • Múltiples interfaces, cada una de las cuales cubre un conjunto de elementos de configuración relacionados.

Una interfaz única es más fácil, pero puede resultar imposible de mantener a medida que se agregan más elementos de configuración al archivo único. Además, el control de acceso no es detallado, por lo que un proceso al que se le concede acceso a la interfaz puede leer todos los elementos de configuración (no se puede conceder acceso a un conjunto parcial de elementos de configuración). Alternativamente, si no se otorga acceso, los elementos de configuración no se pueden leer.

Debido a estos problemas, Android utiliza múltiples interfaces con una única interfaz HAL para un grupo de elementos de configuración relacionados. Por ejemplo, ISurfaceflingerConfigs para elementos de configuración relacionados con surfaceflinger e IBluetoothConfigs para elementos de configuración relacionados con Bluetooth.