The Sensors Multi-HAL is a framework that allows sensors HALs to run alongside other sensor HALs. The Sensors Multi-HAL dynamically loads sensors sub-HALs stored as dynamic libraries on the vendor partition and gives them a callback object that can handle posting events and acquiring and releasing the wake lock. A sensors sub-HAL is a sensors HAL that is built into a shared object on the vendor partition and is used by the multi-HAL framework. These sub-HALs don't depend on one another or on the multi-HAL code that contains the main function for the process.
Sensors Multi-HAL 2.1, available on devices running Android 11 or higher, is an iteration of Sensors Multi-HAL 2.0 that supports loading sub-HALs that can expose the hinge angle sensor type. To support this sensor type, sub-HALs must use the sub-HAL APIs defined in the 2.1 SubHal header.
For devices running Android 13 or higher that use the Sensors AIDL HAL, you can use the multi-HAL shim layer to allow multi-HAL capability. For implementation details, see Using the Sensors Multi-HAL with the Sensors AIDL HAL.
Difference between Sensors Multi-HAL 2 and Sensors HAL 2
Sensors Multi-HAL 2, available on devices running Android
10 or higher,
introduces several abstractions on top of Sensors HAL
2 to make it easier
to interact with HAL APIs. Sensors Multi-HAL 2 introduces the
HalProxy
class to handle implementing the Sensors HAL 2 interface and the
V2_1/SubHal
(or
V2_0/SubHal
)
interface to allow HalProxy
to interact with sub-HALs.
The ISensorsSubHal
interface is different from the
2.1/ISensors.hal
(or
2.0/ISensors.hal
)
interface in the following ways:
- The initialize method passes a
IHalProxyCallback
class instead of two FMQs andISensorsCallback
. - Sub-HALs must implement a debug function for providing debugging information in bug reports.
- Sub-HALs must implement a name function so the loaded sub-HAL can be distinguished from other sub-HALs.
The main difference between Sensors Multi-HAL 2 and Sensors HAL 2 is in the
initialize functions. Instead of providing FMQs, the IHalProxyCallback
interface provides two methods, one method to post sensor events to the sensors
framework and one method to create wake locks. Under the hood, the Sensors
Multi-HAL manages all interactions with the FMQs to ensure timely delivery of
sensor events for all sub-HALs. It's strongly recommended that sub-HALs use the
createScopedWakelock
method to delegate the burden of timing out wake locks to
the Sensors Multi-HAL and to centralize wake lock usage to one common wake lock
for the entire Sensors Multi-HAL, which minimizes locking and unlocking calls.
Sensors Multi-HAL 2 also has some built-in safety features. It handles
situations where the sensor FMQ is full or where the Android sensor framework
restarts and the sensor state needs to be reset. Additionally, when events are
posted to the HalProxy
class but the sensor framework is unable to accept
the events immediately, the Sensors Multi-HAL can move the events to a background
thread to allow work to continue across all sub-HALs while waiting for the
events to be posted.
Source code and reference implementation
All Sensors Multi-HAL code is available in
hardware/interfaces/sensors/common/default/2.X/multihal/
.
Here are pointers to some resources.
HalProxy.h
: TheHalProxy
object is instantiated by Sensors multi-HAL and handles the passing of data from the sub-HALs to the sensor framework.HalProxy.cpp
: The implementation ofHalProxy
contains all logic needed to multiplex communication between sub-HALs and the sensor framework.SubHal.h
: TheISensorsSubHal
interface defines the interface that sub-HALs must follow to be compatible withHalProxy
. The sub-HAL implements the initialize method so that theHalProxyCallback
object can be used forpostEvents
andcreateScopedWakelock
.For Multi-HAL 2.0 implementations, use version 2.0 of
SubHal.h
.hardware/interfaces/sensors/common/default/2.X/multihal/tests/
: These unit tests verify theHalProxy
implementation.hardware/interfaces/sensors/common/default/2.X/multihal/tests/fake_subhal/
: This example sub-HAL implementation uses fake sensors to generate fake data. Useful for testing how multiple sub-HALs interact on a device.
Implementation
This section describes how to implement Sensors Multi-HAL in the following situations:
- Using the Sensors Multi-HAL with the Sensors AIDL HAL
- Implementing Sensors Multi-HAL 2.1
- Porting from Sensors Multi-HAL 2.0 to Multi-HAL 2.1
- Porting from Sensors HAL 2.0
- Porting from Sensors HAL 1.0
- Porting from Sensors Multi-HAL 1.0
Use the Sensors Multi-HAL with the Sensors AIDL HAL
To allow multi-HAL capability with the Sensors AIDL HAL, import the AIDL Multi-HAL shim layer module, which is found in hardware/interfaces/sensors/aidl/default/multihal/. The module handles the conversion between AIDL and HIDL sensors HAL definition types and defines a wrapper around the multi-HAL interface described in Implementing Sensors Multi-HAL 2.1. The AIDL multi-HAL shim layer is compatible with devices that implement Sensors Multi-HAL 2.1.
The AIDL multi-HAL shim layer allows you to expose the head tracker and
limited-axis IMU sensor types in the Sensors AIDL HAL. To use these sensor
types defined by the AIDL HAL interface, set the type
field in the
SensorInfo
struct in the getSensorsList_2_1()
implementation. This is safe
because the integer-backed sensor type fields of the AIDL and HIDL sensors HAL
don't overlap.
Implement Sensors Multi-HAL 2.1
To implement Sensors Multi-HAL 2.1 on a new device, follow these steps:
- Implement the
ISensorsSubHal
interface as described inSubHal.h
. - Implement the
sensorsHalGetSubHal_2_1
method inSubHal.h
. Add a
cc_library_shared
target to build the newly implemented sub-HAL. When adding the target:- Ensure the target is pushed to somewhere on the vendor partition of the device.
- In the config file located at
/vendor/etc/sensors/hals.conf
, add the path to the library on a new line. If necessary, create thehals.conf
file.
For an example
Android.bp
entry for building a sub-HAL library, seehardware/interfaces/sensors/common/default/2.X/multihal/tests/Android.bp
.Remove all
android.hardware.sensors
entries from themanifest.xml
file, which contains the list of supported HALs on the device.Remove all
android.hardware.sensors
service andservice.rc
files from thedevice.mk
file and addandroid.hardware.sensors@2.1-service.multihal
andandroid.hardware.sensors@2.1-service.multihal.rc
toPRODUCT_PACKAGES
.
On boot, HalProxy
starts, looks for the newly implemented sub-HAL, and
initializes it by calling
sensorsHalGetSubHal_2_1
.
Port from Sensors Multi-HAL 2.0 to Multi-HAL 2.1
To port from Multi-HAL 2.0 to Multi-HAL 2.1, implement the
SubHal
interface and recompile your sub-HAL.
These are the differences between the 2.0 and 2.1 SubHal
interfaces:
IHalProxyCallback
uses the types created in version 2.1 of theISensors.hal
specification.- The
initialize()
function passes a newIHalProxyCallback
instead of the one from the 2.0SubHal
interface - Sub-HALs must implement
getSensorsList_2_1
andinjectSensorData_2_1
instead ofgetSensorsList
andinjectSensorData
as these methods use the new types added in version 2.1 of theISensors.hal
specification. - Sub-HALs must expose
sensorsHalGetSubHal_2_1
rather thansensorsHalGetSubHal
for the Multi-HAL to treat them as version 2.1 sub-HALs.
Port from Sensors HAL 2.0
When upgrading to Sensors Multi-HAL 2.0 from Sensors HAL 2.0, ensure the HAL implementation meets the following requirements.
Initialize the HAL
Sensors HAL 2.0 has an initialize function that allows the sensor service to
pass FMQs and a dynamic sensor callback. In Sensors Multi-HAL 2.0, the
initialize()
function passes a single callback that must be used to post
sensor events, obtain wake locks, and notify of dynamic sensor connection and
disconnections.
Post sensor events to the Multi-HAL implementation
Instead of posting sensor events through the FMQ, the sub-HAL must write sensor
events to the
IHalProxyCallback
when sensor events are available.
WAKE_UP events
In Sensors HAL 2.0, the HAL can manage the wake lock for its implementation. In
Sensors Multi-HAL 2.0, the sub-HALs allow the Multi-HAL implementation to
manage wake locks and can request a wake lock to be acquired by invoking
createScopedWakelock
.
A locked scoped wake lock must be acquired and passed to postEvents
when
posting wake up events to the Multi-HAL implementation.
Dynamic sensors
Sensors Multi-HAL 2.0 requires that onDynamicSensorsConnected
and
onDynamicSensorsDisconnected
in
IHalProxyCallback
are called whenever dynamic sensor connections change. These callbacks are
available as part of the IHalProxyCallback
pointer that is provided through
the initialize()
function.
Port from Sensors HAL 1.0
When upgrading to Sensors Multi-HAL 2.0 from Sensors HAL 1.0, ensure the HAL implementation meets the following requirements.
Initialize the HAL
The initialize()
function must be supported to establish the callback between
the sub-HAL and the Multi-HAL implementation.
Expose available sensors
In Sensors Multi-HAL 2.0, the getSensorsList()
function must return the same
value during a single device boot, even across sensors HAL restarts. This allows
the framework to attempt to reestablish sensor connections if the system server
restarts. The value returned by getSensorsList()
can change after the device
performs a reboot.
Post sensor events to the Multi-HAL implementation
In Sensors HAL 2.0, instead of waiting for poll()
to be called, the sub-HAL
must proactively write sensor events to
IHalProxyCallback
whenever sensor events are available.
WAKE_UP events
In Sensors HAL 1.0, the HAL can manage the wake lock for its implementation. In
Sensors Multi-HAL 2.0, the sub-HALs allows the Multi-HAL implementation to
manage wake locks and can request a wake lock to be acquired by invoking
createScopedWakelock
.
A locked scoped wake lock must be acquired and passed to postEvents
when
posting wake up events to the Multi-HAL implementation.
Dynamic sensors
In Sensors HAL 1.0, dynamic sensors are returned through the poll()
function.
Sensors Multi-HAL 2.0 requires that onDynamicSensorsConnected
and
onDynamicSensorsDisconnected
in
IHalProxyCallback
are called whenever dynamic sensor connections change. These callbacks are
available as part of the IHalProxyCallback
pointer that is provided through
the initialize()
function.
Port from Sensors Multi-HAL 1.0
To port an existing implementation from Sensors Multi-HAL 1.0, follow these steps.
- Ensure that the sensors HAL config is located at
/vendor/etc/sensors/hals.conf
. This might involve moving the file located at/system/etc/sensors/hals.conf
. - Remove any references to
hardware/hardware.h
andhardware/sensors.h
as these aren't supported for HAL 2.0. - Port sub-HALs as described in Porting from Sensors Hal 1.0.
- Set Sensors Multi-HAL 2.0 as the designated HAL by following steps 3 and 4 in the Implementing Sensors Mutli-HAL 2.0 section.
Validation
Run VTS
When you've integrated one or more sub-HALs with Sensors Multi-Hal 2.1, use the Vendor Test Suite (VTS) to ensure your sub-HAL implementations meet all the requirements set by the Sensors HAL interface.
To run only the sensors VTS tests when VTS is set up on a host machine, execute the following commands:
vts-tradefed run commandAndExit vts \
--skip-all-system-status-check \
--primary-abi-only \
--skip-preconditions \
--module VtsHalSensorsV2_0Target && \
vts-tradefed run commandAndExit vts \
--skip-all-system-status-check \
--primary-abi-only \
--skip-preconditions \
--module VtsHalSensorsV2_1Target
If you're running the AIDL Multi-HAL shim layer, run VtsAidlHalSensorsTargetTest
.
vts-tradefed run commandAndExit vts \
--skip-all-system-status-check \
--primary-abi-only \
--skip-preconditions \
--module VtsAidlHalSensorsTargetTest
Run unit tests
The unit tests in HalProxy_test.cpp
test HalProxy
using fake sub-HALs that
are instantiated in the unit test and aren't dynamically loaded. When creating a
new sub-HAL, these tests should serve as a guide on how to add unit tests that
verify that the new sub-HAL is implemented properly.
To run the tests, execute the following commands:
cd $ANDROID_BUILD_TOP/hardware/interfaces/sensors/common/default/2.X/multihal/tests
atest
Test with the fake sub-HALs
The fake sub-HALs are dummy implementations of the ISensorsSubHal
interface.
The sub-HALs expose different lists of sensors. When the sensors are activated,
they periodically post automatically generated sensor events to HalProxy
based on the intervals specified in a given sensor request.
The fake sub-HALs can be used to test how the full Multi-HAL code works with other sub-HALs loaded into the system and to stress various aspects of the Sensors Multi-HAL code.
Two fake sub-HALs are available at
hardware/interfaces/sensors/common/default/2.X/multihal/tests/fake_subhal/
.
To build and push the fake sub-HALs to a device, perform the following steps:
Run the following commands to build and push the three different fake sub-HALs to the device:
$ANDROID_BUILD_TOP/hardware/interfaces/sensors/common/default/2.X/multihal/tests/
mma
adb push \ $ANDROID_BUILD_TOP/out/target/product/<device>/symbols/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config1.so \ /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config1.so
adb push \ $ANDROID_BUILD_TOP/out/target/product/<device>/symbols/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config2.so \ /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config2.so
adb push \ $ANDROID_BUILD_TOP/out/target/product/<device>/symbols/vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config3.so \ /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config3.so
Update the sensors HAL config at
/vendor/etc/sensors/hals.conf
with the paths for the fake sub-HALs./vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config1.so /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config2.so /vendor/lib64/android.hardware.sensors@2.X-fakesubhal-config3.so
Restart
HalProxy
and load the new sub-HALs listed in the config.adb shell stop
adb shell start
Debugging
Developers can debug the framework by using the lshal
command. To request the
debug output of the Sensors HAL, run the following command:
adb root
adb shell lshal debug android.hardware.sensors@2.1::ISensors/default
Information about the current state of HalProxy
and its sub-HALs is then
output to the terminal. Shown below is an example of the command output for the
HalProxy
object and fake sub-HALs.
Internal values:
Threads are running: true
Wakelock timeout start time: 200 ms ago
Wakelock timeout reset time: 73208 ms ago
Wakelock ref count: 0
# of events on pending write queue: 0
# of non-dynamic sensors across all subhals: 8
# of dynamic sensors across all subhals: 0
SubHals (2):
Name: FakeSubHal-OnChange
Debug dump:
Available sensors:
Name: Ambient Temp Sensor
Min delay: 40000
Flags: 2
Name: Light Sensor
Min delay: 200000
Flags: 2
Name: Proximity Sensor
Min delay: 200000
Flags: 3
Name: Relative Humidity Sensor
Min delay: 40000
Flags: 2
Name: FakeSubHal-OnChange
Debug dump:
Available sensors:
Name: Ambient Temp Sensor
Min delay: 40000
Flags: 2
Name: Light Sensor
Min delay: 200000
Flags: 2
Name: Proximity Sensor
Min delay: 200000
Flags: 3
Name: Relative Humidity Sensor
Min delay: 40000
Flags: 2
If the number specified for # of events on pending write queue
is a
large number (1000 or more),
this indicates that there are many events pending to be written to the sensors
framework. This indicates the sensor service is deadlocked or has crashed and
isn't processing sensor events, or that a large batch of sensor events was
recently posted from a sub-HAL.
If the wake lock ref count is greater than 0
, this means HalProxy
has
acquired a wake lock. This should only be greater than 0
if a ScopedWakelock
is intentionally being held or if wakeup events were sent to HalProxy
and have
not been processed by the sensor framework.
The file descriptor passed to the debug method of HalProxy
is passed to each
sub-HAL so developers must implement the debug method as part of the
ISensorsSubHal
interface.