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 relevantes deben agruparse y incluirse en un solo archivo .hal
. El uso de HIDL para especificar elementos de configuración
incluye los siguientes beneficios:
- Con versión (para agregar elementos de configuración nuevos, los proveedores o OEMs deben extender de forma explícita el HAL)
- Bien documentada
- 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
Identifica 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 las configuraciones de compilación de 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 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 el nuevo archivo .hal
a los archivos Android.bp
y Android.mk
.
Cómo agregar funciones para 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
:
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:
- Usa los nombres de manera concisa. Evita convertir los nombres de las variables del archivo make en nombres de funciones y ten en cuenta que los prefijos
TARGET_
yBOARD_
ya no son necesarios. - Agregar 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 del elemento de configuración y úsala como el tipo que se muestra. 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 enum (por ejemplo, USE_DEFAULT
) para indicar si el 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. Como alternativa, los propietarios de módulos pueden agregar marcas de compilación estrechamente relacionadas en una struct y tener una función que muestre esa struct (lo que puede reducir la cantidad de llamadas a función).
Por ejemplo, una opción para agregar dos marcas de compilación en una sola 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 a través de 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 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.