You must use HIDL to describe all build flags used for conditionally
compiling the framework. Relevant build flags must be grouped and included in a
single .hal
file. Using HIDL for specifying configuration items
includes the following benefits:
- Versioned (to add new config items, vendors/OEMs must explicitly extend the HAL)
- Well-documented
- Access control using SELinux
- Sanity check for configuration items through the Vendor Test Suite (range check, inter-dependency check among items, etc.)
- Auto-generated APIs in both C++ and Java
Identify build flags used by the framework
Start by identifying the build configs used to conditionally compile the
framework, then abandon obsolete configs to make the set smaller. For example,
the following set of build flags are identified for 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
Create a HAL interface
Build configs for a subsystem are accessed through a HAL interface, while
interfaces for giving configuration values are grouped in the HAL package
android.hardware.configstore
(currently at version 1.0).
For example, to create a HAL interface file for surfaceflinger
, in
hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
:
package android.hardware.configstore@1.0; interface ISurfaceFlingerConfigs { // TO-BE-FILLED-BELOW };
After creating the .hal
file, run
hardware/interfaces/update-makefiles.sh
to add the new
.hal
file to the Android.bp
and
Android.mk
files.
Add functions for build flags
For each build flag, add a new function to the interface. For example, in
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); };
When adding a function:
- Be concise with names. Avoid converting makefile variable
names into function names and keep in mind that
TARGET_
andBOARD_
prefixes are no longer necessary. - Add comments. Help developers understand the purpose of the config item, how it changes framework behavior, valid values, and other relevant information.
Function return types can be
Optional[Bool|String|Int32|UInt32|Int64|UInt64]
. Types are defined
in types.hal
in the same directory and wrap primitive values with a
field that indicates if the value is specified by the HAL; if not, the default
value is used.
struct OptionalString { bool specified; string value; };
When appropriate, define the enum that best represents the type of the
configuration item and use that enum as the return type. In the example above,
the NumBuffers
enum is defined to limit the number of valid
values. When defining such custom data types, add a field or a enum value (for
example, USE_DEFAULT
) for denoting if the value is/isn't specified
by the HAL.
It's not mandatory for a single build flag to become a single function in HIDL. Module owners can alternatively aggregate closely related build flags into a struct and have a function that returns that struct (doing so can reduce number of function calls).
For example, an option for aggregating two build flags into a single struct
in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
is:
interface ISurfaceFlingerConfigs { // other functions here struct SyncConfigs { OptionalInt64 vsyncEventPhaseoffsetNs; OptionalInt64 presentTimeoffsetFromSyncNs; }; getSyncConfigs() generates (SyncConfigs ret); // other functions here };
Alternatives to a single HAL function
As an alternative to using a single HAL function for all build flags, the HAL
interface also provides simple functions such as getBoolean(string
key)
and getInteger(string key)
. The actual
key=value
pairs are stored in separate files and the HAL service
provides values by reading/parsing those files.
While this approach is easy to define, it doesn't include the benefits provided by HIDL (enforced versioning, ease of documentation, access control) and is therefore not recommended.
Single and multiple interfaces
The design of the HAL interface for configuration items presents two choices:
- A single interface that covers all configuration items
- Multiple interfaces, each of which covers a set of related configuration items
A single interface is easier but can become unmaintainable as more configuration items are added to the single file. In addition, access control isn't fine-grained, so a process that's granted access to the interface can read all configuration items (access to a partial set of configuration items can't be granted). Alternatively, if access isn't granted, configuration items can't be read.
Because of these issues, Android uses multiple interfaces with a single HAL
interface for a group of related configuration items. For example,
ISurfaceflingerConfigs
for surfaceflinger
-related
configuration items, and IBluetoothConfigs
for Bluetooth-related
configuration items.