Debes usar el HIDL para describir todas las marcas de compilación que se usan en la compilación condicional del framework. Las marcas de compilación relevantes deben agruparse y incluirse en un solo archivo .hal
. El uso del HIDL para especificar elementos de configuración incluye los siguientes beneficios:
- Con control de versiones (para agregar elementos de configuración nuevos, los proveedores y OEM deben extender la HAL de forma explícita)
- Bien documentados
- Control de acceso con SELinux
- Realiza una verificación de coherencia de los elementos de configuración a través del paquete de pruebas del proveedor (verificación de rango, verificación de interdependencia entre elementos, etcétera).
- APIs generadas automáticamente en C++ y Java
Cómo identificar las marcas de compilación que usa el framework
Comienza por identificar las configuraciones de compilación que se usan para compilar de forma condicional el framework y, luego, abandona 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 puede acceder a los parámetros de configuración de compilación de un subsistema a través de una interfaz de HAL, mientras que las interfaces para proporcionar valores de configuración se agrupan en el paquete de 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
, 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 archivo .hal
nuevo a los archivos Android.bp
y Android.mk
.
Agrega 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 agregues una función, haz lo siguiente:
- Sé breve con los nombres. Evita convertir los nombres de variables de archivos Make en nombres de funciones. 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 relevante.
Los tipos de datos que se muestran de la función pueden ser Optional[Bool|String|Int32|UInt32|Int64|UInt64]
. Los tipos se definen en types.hal
en el mismo directorio y unen valores primitivos con un campo que indica si el HAL especifica el valor. De lo contrario, se usa el valor predeterminado.
struct OptionalString { bool specified; string value; };
Cuando corresponda, define la enumeración que mejor represente el tipo de elemento de configuración y usa esa enumeración como el tipo de datos que se muestra. En el ejemplo anterior, se define la enum 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 o no el valor.
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 a un struct y tener una función que muestre ese struct (si lo haces, se puede 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 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 de HAL
Como alternativa al uso de una sola función de HAL para todas las marcas de compilación, la interfaz de 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 de HAL proporciona valores mediante la lectura o el análisis de esos archivos.
Si bien este enfoque es fácil de definir, no incluye los beneficios que proporciona HIDL (control de acceso, versión forzada, facilidad de documentación) y, por lo tanto, no se recomienda.
Interfaces únicas y múltiples
El diseño de la interfaz de la HAL para los 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 elementos de configuración relacionados
Una sola interfaz es más fácil, pero puede volverse inmanejable 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 otorgó 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 de HAL para un grupo de elementos de configuración relacionados. Por ejemplo, ISurfaceflingerConfigs
para los elementos de configuración relacionados con surfaceflinger
y IBluetoothConfigs
para los elementos de configuración relacionados con Bluetooth.