Debes usar HIDL para describir todas las marcas de compilación que se usan para compilar el framework de forma condicional. Las marcas de compilación pertinentes se deben agrupar y deben incluirse en un solo archivo .hal. El uso de HIDL para especificar elementos de configuración incluye los siguientes beneficios:
- Control de versiones (para agregar elementos de configuración nuevos, los proveedores o los OEM deben extender la HAL de forma explícita)
- Con documentación suficiente
- Control de acceso con SELinux
- Verificación de cordura para elementos de configuración a través del Vendor Test Suite (verificación de rango, verificación de interdependencia entre elementos, etcétera)
- APIs generadas automáticamente en C++ y Java
Identifica las marcas de compilación que usa el framework
Comienza por identificar las configuraciones de compilación que se usan para compilar el framework de forma condicional y, luego, abandona las configuraciones obsoletas para reducir el conjunto. Por ejemplo, se identifica el siguiente conjunto de marcas de compilación para surfaceflinger:
TARGET_USES_HWC2TARGET_BOARD_PLATFORMTARGET_DISABLE_TRIPLE_BUFFERINGTARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYSNUM_FRAMEBUFFER_SURFACE_BUFFERSTARGET_RUNNING_WITHOUT_SYNC_FRAMEWORKVSYNC_EVENT_PHASE_OFFSET_NSSF_VSYNC_EVENT_PHASE_OFFSET_NSPRESENT_TIME_OFFSET_FROM_VSYNC_NSMAX_VIRTUAL_DISPLAY_DIMENSION
Crea 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, haz lo siguiente:
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 el nuevo archivo .hal a los archivos Android.bp y Android.mk.
Agrega funciones para las marcas de compilación
Para cada marca de compilación, agrega una función nueva a la interfaz. Por ejemplo, en hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal, haz lo siguiente:
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 agregues una función, haz lo siguiente:
- Sé conciso con los nombres. Evita convertir nombres de variables de makefile en nombres de funciones y ten en cuenta que los prefijos
TARGET_yBOARD_ya no son necesarios. - Agrega comentarios. Ayuda a los desarrolladores a comprender el propósito del elemento de configuración, cómo cambia el comportamiento del framework, los valores válidos y otra información pertinente.
Los tipos de valor que muestra la función pueden ser Optional[Bool|String|Int32|UInt32|Int64|UInt64]. Los tipos se definen en types.hal en el mismo directorio y ajustan los valores primitivos con un campo que indica si la HAL especifica el valor; si no es así, se usa el valor predeterminado.
struct OptionalString {
bool specified;
string value;
};
Cuando corresponda, define la enumeración que mejor represente el tipo del elemento de configuración y usa esa enumeración como el tipo de datos que se devuelve. En el ejemplo anterior, se define la enumeración NumBuffers para limitar la cantidad de valores válidos. Cuando definas esos tipos de datos personalizados, agrega un campo o un valor de enumeración (por ejemplo, USE_DEFAULT) para indicar si la HAL especifica el valor.
No es obligatorio que una sola marca de compilación se convierta en una sola función en HIDL. Los propietarios de módulos también pueden agregar marcas de compilación relacionadas en una estructura y tener una función que muestre esa estructura (esto puede reducir la cantidad de llamadas a funciones).
Por ejemplo, una opción para agregar dos marcas de compilación en una sola estructura en hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal es la siguiente:
interface ISurfaceFlingerConfigs {
// other functions here
struct SyncConfigs {
OptionalInt64 vsyncEventPhaseoffsetNs;
OptionalInt64 presentTimeoffsetFromSyncNs;
};
getSyncConfigs() generates (SyncConfigs ret);
// other functions here
};
Alternativas a una sola función HAL
Como alternativa a usar una sola función HAL para todas las marcas 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 o analizando esos archivos.
Si bien este enfoque es fácil de definir, no incluye los beneficios que proporciona HIDL (control de versiones forzado, 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 sola interfaz que cubre todos los elementos de configuración
- Varias interfaces, cada una de las cuales cubre un conjunto de elementos de configuración relacionados
Una sola interfaz es más fácil, pero puede volverse 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 que tiene acceso a la interfaz puede leer todos los elementos de configuración (no se puede otorgar acceso a un conjunto parcial de elementos de configuración). Como alternativa, si no se otorga acceso, no se pueden leer los elementos de configuración.
Debido a estos problemas, Android usa varias interfaces con una sola interfaz HAL para un grupo de elementos de configuración relacionados. Por ejemplo, ISurfaceflingerConfigs para elementos de configuración relacionados con surfaceflinger y IBluetoothConfigs para elementos de configuración relacionados con Bluetooth.