Merge "Add VtsHalNeuralnetworksV1_3TargetTest to TEST_MAPPING"
diff --git a/Android.bp b/Android.bp
index 70e0574..f64968f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -26,7 +26,7 @@
],
header_libs: [
- "libhidl_gtest_helpers",
+ "libhidl_gtest_helper",
],
group_static_libs: true,
diff --git a/current.txt b/current.txt
index ef1228f..8953d51 100644
--- a/current.txt
+++ b/current.txt
@@ -586,8 +586,16 @@
# HALs released in Android R
07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
+26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
+db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice
b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types
544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator
5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback
033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
+41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types
+a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio
+a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
+15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse
+
diff --git a/health/1.0/vts/functional/Android.bp b/health/1.0/vts/functional/Android.bp
index c14dcee..be2d206 100644
--- a/health/1.0/vts/functional/Android.bp
+++ b/health/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["VtsHalHealthV1_0TargetTest.cpp"],
static_libs: ["android.hardware.health@1.0"],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
index 335d15d..b985a9f 100644
--- a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
+++ b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
@@ -18,11 +18,11 @@
#include <android/hardware/health/1.0/IHealth.h>
#include <android/hardware/health/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <log/log.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
using IHealth = ::android::hardware::health::V1_0::IHealth;
@@ -30,25 +30,10 @@
using ::android::sp;
-// Test environment for Health HIDL HAL.
-class HealthHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static HealthHidlEnvironment* Instance() {
- static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IHealth>(); }
- private:
- HealthHidlEnvironment() {}
-};
-
-class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HealthHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- health = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(
- HealthHidlEnvironment::Instance()->getServiceName<IHealth>());
+ health = IHealth::getService(GetParam());
ASSERT_NE(health, nullptr);
health->init(config,
[&](const auto& halConfigOut) { config = halConfigOut; });
@@ -61,7 +46,7 @@
/**
* Ensure EnergyCounter call returns positive energy counter or NOT_SUPPORTED
*/
-TEST_F(HealthHidlTest, TestEnergyCounter) {
+TEST_P(HealthHidlTest, TestEnergyCounter) {
Result result;
int64_t energy = 0;
health->energyCounter([&](Result ret, int64_t energyOut) {
@@ -73,11 +58,7 @@
ASSERT_TRUE(result != Result::SUCCESS || energy > 0);
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- HealthHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- ALOGI("Test result = %d", status);
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, HealthHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/health/2.0/README.md b/health/2.0/README.md
index 4ecfb9a..8a7c922 100644
--- a/health/2.0/README.md
+++ b/health/2.0/README.md
@@ -1,3 +1,8 @@
+# Implement the 2.1 HAL instead!
+
+It is strongly recommended that you implement the 2.1 HAL directly. See
+`hardware/interfaces/health/2.1/README.md` for more details.
+
# Upgrading from Health 1.0 HAL
1. Remove `android.hardware.health@1.0*` from `PRODUCT_PACKAGES`
diff --git a/health/2.1/README.md b/health/2.1/README.md
new file mode 100644
index 0000000..5a19d7b
--- /dev/null
+++ b/health/2.1/README.md
@@ -0,0 +1,245 @@
+# Implementing Health 2.1 HAL
+
+1. Install common binderized service. The binderized service `dlopen()`s
+ passthrough implementations on the device, so there is no need to write
+ your own.
+
+ ```mk
+ # Install default binderized implementation to vendor.
+ PRODUCT_PACKAGES += android.hardware.health@2.1-service
+ ```
+
+1. Delete existing VINTF manifest entry. Search for `android.hardware.health` in
+ your device manifest, and delete the whole `<hal>` entry for older versions
+ of the HAL. Instead, when `android.hardware.health@2.1-service` is installed,
+ a VINTF manifest fragment is installed to `/vendor/etc/vintf`, so there is
+ no need to manually specify it in your device manifest. See
+ [Manifest fragments](https://source.android.com/devices/architecture/vintf/objects#manifest-fragments)
+ for details.
+
+1. Install the proper passthrough implemetation.
+
+ 1. If you want to use default implementation:
+
+ ```mk
+ # Install default passthrough implementation to vendor.
+ PRODUCT_PACKAGES += android.hardware.health@2.1-impl
+ ```
+
+ You are done. Otherwise, go to the next step.
+
+ 1. If you want to write your own implementation,
+
+ 1. Copy skeleton implementation from the [appendix](#impl).
+
+ 1. Modify the implementation to suit your needs.
+
+ * If you have a board or device specific `libhealthd`, see
+ [Upgrading with a customized libhealthd](#update-from-1-0).
+ * If you are upgrading from 1.0 health HAL, see
+ [Upgrading from Health HAL 1.0](#update-from-1-0).
+ * If you are upgrading from a customized 2.0 health HAL
+ implementation, See
+ [Upgrading from Health HAL 2.0](#update-from-2-0).
+
+ 1. [Update necessary SELinux permissions](#selinux).
+
+ 1. [Fix `/charger` symlink](#charger-symlink).
+
+# Upgrading with a customized libhealthd or from Health HAL 1.0 {#update-from-1-0}
+
+`libhealthd` contains two functions: `healthd_board_init()` and
+`healthd_board_battery_update()`. Similarly, Health HAL 1.0 contains `init()`
+and `update()`, with an additional `energyCounter()` function.
+
+* `healthd_board_init()` / `@1.0::IHealth.init()` should be called before
+ passing the `healthd_config` struct to your `HealthImpl` class. See
+ `HIDL_FETCH_IHealth` in [`HealthImpl.cpp`](#health_impl_cpp).
+
+* `healthd_board_battery_update()` / `@1.0::IHealth.update()` should be called
+ in `HealthImpl::UpdateHealthInfo()`. Example:
+
+ ```c++
+ void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
+ struct BatteryProperties props;
+ convertFromHealthInfo(health_info->legacy.legacy, &props);
+ healthd_board_battery_update(&props);
+ convertToHealthInfo(&props, health_info->legacy.legacy);
+ }
+ ```
+ For efficiency, you should move code in `healthd_board_battery_update` to
+ `HealthImpl::UpdateHealthInfo` and modify `health_info` directly to avoid
+ conversion to `BatteryProperties`.
+
+* Code for `@1.0::IHealth.energyCounter()` should be moved to
+ `HealthImpl::getEnergyCounter()`. Example:
+
+ ```c++
+ Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+ int64_t energy = /* ... */;
+ _hidl_cb(Result::SUCCESS, energy);
+ return Void();
+ }
+ ```
+
+# Upgrading from Health HAL 2.0 {#update-from-2-0}
+
+* If you have implemented `healthd_board_init()` and/or
+ `healthd_board_battery_update()` (instead of using `libhealthd.default`),
+ see [the section above](#update-from-1-0)
+ for instructions to convert them.
+
+* If you have implemented `get_storage_info()` and/or `get_disk_stats()`
+ (instead of using libhealthstoragedefault), implement `HealthImpl::getDiskStats`
+ and/or `HealthImpl::getStorageInfo` directly. There is no need to override
+ `HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
+ `getDiskStats` and `getStorageInfo` to retrieve storage information.
+
+# Update necessary SELinux permissions {#selinux}
+
+For example (replace `<device>` with the device name):
+```
+# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
+# Add device specific permissions to hal_health_default domain, especially
+# if a device-specific libhealthd is used and/or device-specific storage related
+# APIs are implemented.
+```
+
+# Fix `/charger` symlink {#charger-symlink}
+If you are using `/charger` in your `init.rc` scripts, it is recommended
+(required for devices running in Android R) that the path is changed to
+`/system/bin/charger` instead.
+
+Search for `service charger` in your device configuration directory to see if
+this change applies to your device. Below is an example of how the script should
+look like:
+
+```
+service charger /system/bin/charger
+ class charger
+ user system
+ group system wakelock input
+ capabilities SYS_BOOT
+ file /dev/kmsg w
+ file /sys/fs/pstore/console-ramoops-0 r
+ file /sys/fs/pstore/console-ramoops r
+ file /proc/last_kmsg r
+```
+
+# Appendix: sample code for the implementation {#impl}
+
+## `device/<manufacturer>/<device>/health/Android.bp` {#android_bp}
+
+```bp
+cc_library_shared {
+ name: "android.hardware.health@2.1-impl-<device>",
+ stem: "android.hardware.health@2.0-impl-2.1-<device>",
+
+ // Install to vendor and recovery.
+ proprietary: true,
+ recovery_available: true,
+
+ relative_install_path: "hw",
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.health@2.1",
+ "android.hardware.health@2.0",
+ ],
+
+ static_libs: [
+ "android.hardware.health@1.0-convert",
+ "libbatterymonitor",
+ "libhealthloop",
+ "libhealth2impl",
+ // "libhealthd.<device>"
+ ],
+
+ srcs: [
+ "HealthImpl.cpp",
+ ],
+
+ // No vintf_fragments because both -impl and -service should have been
+ // installed.
+}
+```
+
+## `device/<manufacturer>/<device>/health/HealthImpl.cpp` {#health_impl_cpp}
+
+```c++
+#include <memory>
+#include <string_view>
+
+#include <health/utils.h>
+#include <health2impl/Health.h>
+#include <hidl/Status.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::health::InitHealthdConfig;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hidl::base::V1_0::IBase;
+
+using namespace std::literals;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// android::hardware::health::V2_1::implementation::Health implements most
+// defaults. Uncomment functions that you need to override.
+class HealthImpl : public Health {
+ public:
+ HealthImpl(std::unique_ptr<healthd_config>&& config)
+ : Health(std::move(config)) {}
+
+ // A subclass can override this if these information should be retrieved
+ // differently.
+ // Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+ // Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+ // Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+ // Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+ // Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+ // Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+ // Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+ // Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+ // Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+ // Functions introduced in Health HAL 2.1.
+ // Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
+ // Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
+ // Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
+
+ protected:
+ // A subclass can override this to modify any health info object before
+ // returning to clients. This is similar to healthd_board_battery_update().
+ // By default, it does nothing.
+ // void UpdateHealthInfo(HealthInfo* health_info) override;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
+
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
+ using ::android::hardware::health::V2_1::implementation::HealthImpl;
+ if (instance != "default"sv) {
+ return nullptr;
+ }
+ auto config = std::make_unique<healthd_config>();
+ InitHealthdConfig(config.get());
+
+ // healthd_board_init(config.get());
+
+ return new HealthImpl(std::move(config));
+}
+```
diff --git a/health/2.1/default/Android.bp b/health/2.1/default/Android.bp
new file mode 100644
index 0000000..3649853
--- /dev/null
+++ b/health/2.1/default/Android.bp
@@ -0,0 +1,81 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "android.hardware.health@2.1-impl-defaults",
+ relative_install_path: "hw",
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.health@2.1",
+ "android.hardware.health@2.0",
+ ],
+
+ static_libs: [
+ "android.hardware.health@1.0-convert",
+ "libbatterymonitor",
+ "libhealthloop",
+ "libhealth2impl",
+ ],
+}
+
+// Default passthrough implementation of the health@2.1 HAL.
+// Passhtrough implementations of the health@2.1 HAL must be installed in
+// vendor in order to support charger.
+// Passhtrough implementations of the health@2.1 HAL must be installed in
+// recovery in order to allow recovery to check battery status.
+// See README.md for details.
+cc_library_shared {
+ name: "android.hardware.health@2.1-impl",
+ stem: "android.hardware.health@2.0-impl-2.1",
+
+ // Only vendor and recovery variants are allowed, not core.
+ vendor: true,
+ recovery_available: true,
+
+ defaults: ["android.hardware.health@2.1-impl-defaults"],
+
+ srcs: [
+ "impl.cpp",
+ ],
+
+ // No vintf_fragments because both -impl and -service should have been
+ // installed.
+}
+
+// Default binderized service of the health@2.1 HAL.
+// This binderized implementation dlopen()s the passthrough implementation,
+// so there is no need to implement your own.
+cc_binary {
+ name: "android.hardware.health@2.1-service",
+ vendor: true,
+ defaults: ["android.hardware.health@2.1-impl-defaults"],
+ init_rc: ["android.hardware.health@2.1-service.rc"],
+
+ srcs: [
+ "service.cpp",
+ ],
+
+ vintf_fragments: [
+ "android.hardware.health@2.1.xml"
+ ],
+
+ overrides: [
+ "healthd",
+ ],
+}
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
new file mode 100644
index 0000000..917f1c2
--- /dev/null
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -0,0 +1,6 @@
+service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
+ class hal
+ user system
+ group system
+ capabilities WAKE_ALARM
+ file /dev/kmsg w
diff --git a/health/2.1/default/android.hardware.health@2.1.xml b/health/2.1/default/android.hardware.health@2.1.xml
new file mode 100644
index 0000000..34fdca6
--- /dev/null
+++ b/health/2.1/default/android.hardware.health@2.1.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.health</name>
+ <transport>hwbinder</transport>
+ <fqname>@2.1::IHealth/default</fqname>
+ </hal>
+</manifest>
diff --git a/health/2.1/default/impl.cpp b/health/2.1/default/impl.cpp
new file mode 100644
index 0000000..7389a21
--- /dev/null
+++ b/health/2.1/default/impl.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <string_view>
+
+#include <health/utils.h>
+#include <health2impl/Health.h>
+
+using ::android::sp;
+using ::android::hardware::health::InitHealthdConfig;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hardware::health::V2_1::implementation::Health;
+
+using namespace std::literals;
+
+// Passthrough implementation of the health service. Use default configuration.
+// It does not invoke callbacks unless update() is called explicitly. No
+// background thread is spawned to handle callbacks.
+//
+// The passthrough implementation is only allowed in recovery mode, charger, and
+// opened by the hwbinder service.
+// If Android is booted normally, the hwbinder service is used instead.
+//
+// This implementation only implements the "default" instance. It rejects
+// other instance names.
+// Note that the Android framework only reads values from the "default"
+// health HAL 2.1 instance.
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
+ if (instance != "default"sv) {
+ return nullptr;
+ }
+ auto config = std::make_unique<healthd_config>();
+ InitHealthdConfig(config.get());
+
+ // This implementation uses default config. If you want to customize it
+ // (e.g. with healthd_board_init), do it here.
+
+ return new Health(std::move(config));
+}
diff --git a/health/2.1/default/service.cpp b/health/2.1/default/service.cpp
new file mode 100644
index 0000000..f8334c5
--- /dev/null
+++ b/health/2.1/default/service.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "android.hardware.health@2.1-service"
+
+#include <android-base/logging.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health2impl/BinderHealth.h>
+
+using ::android::sp;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hardware::health::V2_1::implementation::BinderHealth;
+using IHealth_2_0 = ::android::hardware::health::V2_0::IHealth;
+
+static constexpr const char* gInstanceName = "default";
+
+int main(int /* argc */, char* /* argv */[]) {
+ sp<IHealth> passthrough =
+ IHealth::castFrom(IHealth_2_0::getService(gInstanceName, true /* getStub */));
+ CHECK(passthrough != nullptr)
+ << "Cannot find passthrough implementation of health 2.1 HAL for instance "
+ << gInstanceName;
+ sp<BinderHealth> binder = new BinderHealth(gInstanceName, passthrough);
+ return binder->StartLoop();
+}
diff --git a/health/utils/libhealth2impl/Android.bp b/health/utils/libhealth2impl/Android.bp
new file mode 100644
index 0000000..14374a2
--- /dev/null
+++ b/health/utils/libhealth2impl/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A helper library for health@2.x HAL implementation.
+// HAL implementations can link to this library and extend the Health class.
+cc_library_static {
+ name: "libhealth2impl",
+ vendor_available: true,
+ recovery_available: true,
+ srcs: [
+ "BinderHealth.cpp",
+ "HalHealthLoop.cpp",
+ "Health.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.health@2.1",
+ "android.hardware.health@2.0",
+ ],
+ static_libs: [
+ "libbatterymonitor",
+ "libhealthloop",
+ "android.hardware.health@1.0-convert",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_static_lib_headers: [
+ "libbatterymonitor",
+ "libhealthloop",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
diff --git a/health/utils/libhealth2impl/BinderHealth.cpp b/health/utils/libhealth2impl/BinderHealth.cpp
new file mode 100644
index 0000000..625d0e0
--- /dev/null
+++ b/health/utils/libhealth2impl/BinderHealth.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <health2impl/BinderHealth.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/Health.h>
+
+using android::hardware::handleTransportPoll;
+using android::hardware::IPCThreadState;
+using android::hardware::setupTransportPolling;
+
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+bool IsDeadObjectLogged(const Return<void>& ret) {
+ if (ret.isOk()) return false;
+ if (ret.isDeadObject()) return true;
+ LOG(ERROR) << "Cannot call healthInfoChanged* on callback: " << ret.description();
+ return false;
+}
+
+BinderHealth::BinderHealth(const std::string& name, const sp<IHealth>& impl)
+ : HalHealthLoop(name, impl) {
+ CHECK_NE(this, impl.get());
+ CHECK(!impl->isRemote());
+}
+
+//
+// Methods that handle callbacks.
+//
+
+Return<Result> BinderHealth::registerCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
+ if (callback == nullptr) {
+ return Result::SUCCESS;
+ }
+
+ Callback* wrapped = nullptr;
+ {
+ std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+ wrapped = callbacks_.emplace_back(Wrap(callback)).get();
+ // unlock
+ }
+
+ auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
+ if (!linkRet.withDefault(false)) {
+ LOG(WARNING) << __func__ << "Cannot link to death: "
+ << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
+ // ignore the error
+ }
+
+ getHealthInfo_2_1([&](auto res, const auto& health_info) {
+ if (res != Result::SUCCESS) {
+ LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
+ return;
+ }
+ auto ret = wrapped->Notify(health_info);
+ if (IsDeadObjectLogged(ret)) {
+ // Remove callback reference.
+ std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+ auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
+ [wrapped](const auto& cb) { return cb.get() == wrapped; });
+ if (it != callbacks_.end()) {
+ callbacks_.erase(it);
+ }
+ // unlock
+ }
+ });
+
+ return Result::SUCCESS;
+}
+
+bool BinderHealth::unregisterCallbackInternal(const sp<IBase>& callback) {
+ if (callback == nullptr) {
+ return false;
+ }
+
+ bool removed = false;
+ std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+ for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+ if (interfacesEqual((*it)->Get(), callback)) {
+ it = callbacks_.erase(it);
+ removed = true;
+ } else {
+ ++it;
+ }
+ }
+ (void)callback->unlinkToDeath(this).isOk(); // ignore errors
+ return removed;
+}
+
+Return<Result> BinderHealth::update() {
+ Result result = service()->update();
+ if (result != Result::SUCCESS) return result;
+ getHealthInfo_2_1([&](auto res, const auto& health_info) {
+ if (res != Result::SUCCESS) {
+ result = res;
+ return;
+ }
+ OnHealthInfoChanged(health_info);
+ });
+ return result;
+}
+
+Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
+ return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
+}
+
+void BinderHealth::OnHealthInfoChanged(const HealthInfo& health_info) {
+ // Notify all callbacks
+ std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
+ for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+ auto ret = (*it)->Notify(health_info);
+ if (IsDeadObjectLogged(ret)) {
+ it = callbacks_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ lock.unlock();
+
+ // adjusts uevent / wakealarm periods
+ HalHealthLoop::OnHealthInfoChanged(health_info);
+}
+
+void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
+ (void)unregisterCallbackInternal(who.promote());
+}
+
+void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
+ if (binder_fd_ >= 0) {
+ handleTransportPoll(binder_fd_);
+ }
+}
+
+void BinderHealth::Init(struct healthd_config* config) {
+ // Set up epoll and get uevent / wake alarm periods
+ HalHealthLoop::Init(config);
+
+ LOG(INFO) << instance_name() << " instance initializing with healthd_config...";
+
+ binder_fd_ = setupTransportPolling();
+
+ if (binder_fd_ >= 0) {
+ auto binder_event = [](auto* health_loop, uint32_t epevents) {
+ static_cast<BinderHealth*>(health_loop)->BinderEvent(epevents);
+ };
+ if (RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
+ PLOG(ERROR) << instance_name() << " instance: Register for binder events failed";
+ }
+ }
+
+ CHECK_EQ(registerAsService(instance_name()), android::OK)
+ << instance_name() << ": Failed to register HAL";
+
+ LOG(INFO) << instance_name() << ": Hal init done";
+}
+
+int BinderHealth::PrepareToWait(void) {
+ IPCThreadState::self()->flushCommands();
+ return HalHealthLoop::PrepareToWait();
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealth2impl/HalHealthLoop.cpp b/health/utils/libhealth2impl/HalHealthLoop.cpp
new file mode 100644
index 0000000..3901a76
--- /dev/null
+++ b/health/utils/libhealth2impl/HalHealthLoop.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <health2impl/HalHealthLoop.h>
+
+#include <android-base/logging.h>
+#include <hal_conversion.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Health.h>
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::handleTransportPoll;
+using android::hardware::IPCThreadState;
+using android::hardware::setupTransportPolling;
+
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+void HalHealthLoop::Init(struct healthd_config* config) {
+ // Retrieve healthd_config from the HAL.
+ service_->getHealthConfig([config](auto res, const auto& health_config) {
+ CHECK(res == Result::SUCCESS);
+
+ convertFromHealthConfig(health_config.battery, config);
+ config->boot_min_cap = health_config.bootMinCap;
+
+ // Leave screen_on empty because it is handled in GetScreenOn below.
+
+ // Leave ignorePowerSupplyNames empty because it isn't
+ // used by clients of health HAL.
+ });
+}
+
+void HalHealthLoop::Heartbeat(void) {
+ // noop
+}
+
+void HalHealthLoop::ScheduleBatteryUpdate() {
+ // ignore errors. impl may not be able to handle any callbacks, so
+ // update() may return errors.
+ Result res = service_->update();
+ if (res != Result::SUCCESS) {
+ LOG(WARNING) << "update() on the health HAL implementation failed with " << toString(res);
+ }
+
+ service_->getHealthInfo_2_1([this](auto res, const auto& health_info) {
+ CHECK(res == Result::SUCCESS)
+ << "getHealthInfo_2_1() on the health HAL implementation failed with "
+ << toString(res);
+ this->OnHealthInfoChanged(health_info);
+ });
+}
+
+int HalHealthLoop::PrepareToWait() {
+ return -1;
+}
+
+void HalHealthLoop::OnHealthInfoChanged(const HealthInfo& health_info) {
+ set_charger_online(health_info);
+ AdjustWakealarmPeriods(charger_online());
+}
+
+void HalHealthLoop::set_charger_online(const HealthInfo& health_info) {
+ const auto& props = health_info.legacy.legacy;
+ charger_online_ =
+ props.chargerAcOnline || props.chargerUsbOnline || props.chargerWirelessOnline;
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealth2impl/Health.cpp b/health/utils/libhealth2impl/Health.cpp
new file mode 100644
index 0000000..f4684ae
--- /dev/null
+++ b/health/utils/libhealth2impl/Health.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <health2impl/Health.h>
+
+#include <functional>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/IHealthInfoCallback.h>
+#include <android/hardware/health/2.0/types.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <hal_conversion.h>
+#include <healthd/healthd.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/HalHealthLoop.h>
+
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_1::IHealth;
+
+using ScreenOn = decltype(healthd_config::screen_on);
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+/*
+// If you need to call healthd_board_init, construct the Health instance with
+// the healthd_config after calling healthd_board_init:
+struct healthd_config* init_config(struct healthd_config* config) {
+ healthd_board_init(config);
+ return config;
+}
+class MyHealth : public Health {
+ MyHealth(struct healthd_config* config) :
+ Health(init_config(config)) {}
+};
+*/
+
+Health::Health(std::unique_ptr<healthd_config>&& config) : healthd_config_(std::move(config)) {
+ battery_monitor_.init(healthd_config_.get());
+}
+
+//
+// Callbacks are not supported by the passthrough implementation.
+//
+
+Return<Result> Health::registerCallback(const sp<V2_0::IHealthInfoCallback>&) {
+ return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Health::unregisterCallback(const sp<V2_0::IHealthInfoCallback>&) {
+ return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Health::update() {
+ Result result = Result::UNKNOWN;
+ getHealthInfo_2_1([&](auto res, const auto& /* health_info */) {
+ result = res;
+ if (res != Result::SUCCESS) {
+ LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
+ return;
+ }
+
+ battery_monitor_.logValues();
+ });
+ return result;
+}
+
+//
+// Getters.
+//
+
+template <typename T>
+static Return<void> GetProperty(BatteryMonitor* monitor, int id, T defaultValue,
+ const std::function<void(Result, T)>& callback) {
+ struct BatteryProperty prop;
+ T ret = defaultValue;
+ Result result = Result::SUCCESS;
+ status_t err = monitor->getProperty(static_cast<int>(id), &prop);
+ if (err != OK) {
+ LOG(DEBUG) << "getProperty(" << id << ")"
+ << " fails: (" << err << ") " << strerror(-err);
+ } else {
+ ret = static_cast<T>(prop.valueInt64);
+ }
+ switch (err) {
+ case OK:
+ result = Result::SUCCESS;
+ break;
+ case NAME_NOT_FOUND:
+ result = Result::NOT_SUPPORTED;
+ break;
+ default:
+ result = Result::UNKNOWN;
+ break;
+ }
+ callback(result, static_cast<T>(ret));
+ return Void();
+}
+
+Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
+ return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
+}
+
+Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
+ return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
+}
+
+Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
+ return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
+}
+
+Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
+ return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
+}
+
+Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+ return GetProperty<int64_t>(&battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
+}
+
+Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
+ return GetProperty(&battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN,
+ _hidl_cb);
+}
+
+Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
+ // This implementation does not support StorageInfo. An implementation may extend this
+ // class and override this function to support storage info.
+ _hidl_cb(Result::NOT_SUPPORTED, {});
+ return Void();
+}
+
+Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
+ // This implementation does not support DiskStats. An implementation may extend this
+ // class and override this function to support disk stats.
+ _hidl_cb(Result::NOT_SUPPORTED, {});
+ return Void();
+}
+
+template <typename T, typename Method>
+static inline void GetHealthInfoField(Health* service, Method func, T* out) {
+ *out = T{};
+ std::invoke(func, service, [out](Result result, const T& value) {
+ if (result == Result::SUCCESS) *out = value;
+ });
+}
+
+Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
+ return getHealthInfo_2_1(
+ [&](auto res, const auto& health_info) { _hidl_cb(res, health_info.legacy); });
+}
+
+Return<void> Health::getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) {
+ battery_monitor_.updateValues();
+
+ HealthInfo health_info = battery_monitor_.getHealthInfo_2_1();
+
+ // Fill in storage infos; these aren't retrieved by BatteryMonitor.
+ GetHealthInfoField(this, &Health::getStorageInfo, &health_info.legacy.storageInfos);
+ GetHealthInfoField(this, &Health::getDiskStats, &health_info.legacy.diskStats);
+
+ // A subclass may want to update health info struct before returning it.
+ UpdateHealthInfo(&health_info);
+
+ _hidl_cb(Result::SUCCESS, health_info);
+ return Void();
+}
+
+Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+ if (handle == nullptr || handle->numFds == 0) {
+ return Void();
+ }
+
+ int fd = handle->data[0];
+ battery_monitor_.dumpState(fd);
+ getHealthInfo_2_1([fd](auto res, const auto& info) {
+ android::base::WriteStringToFd("\ngetHealthInfo -> ", fd);
+ if (res == Result::SUCCESS) {
+ android::base::WriteStringToFd(toString(info), fd);
+ } else {
+ android::base::WriteStringToFd(toString(res), fd);
+ }
+ android::base::WriteStringToFd("\n", fd);
+ });
+
+ fsync(fd);
+ return Void();
+}
+
+Return<void> Health::getHealthConfig(getHealthConfig_cb _hidl_cb) {
+ HealthConfig config = {};
+ convertToHealthConfig(healthd_config_.get(), config.battery);
+ config.bootMinCap = static_cast<int32_t>(healthd_config_->boot_min_cap);
+
+ _hidl_cb(Result::SUCCESS, config);
+ return Void();
+}
+
+Return<void> Health::shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) {
+ if (!healthd_config_->screen_on) {
+ _hidl_cb(Result::NOT_SUPPORTED, true);
+ return Void();
+ }
+
+ Result returned_result = Result::UNKNOWN;
+ bool screen_on = true;
+ getHealthInfo_2_1([&](auto res, const auto& health_info) {
+ returned_result = res;
+ if (returned_result != Result::SUCCESS) return;
+
+ struct BatteryProperties props = {};
+ V1_0::hal_conversion::convertFromHealthInfo(health_info.legacy.legacy, &props);
+ screen_on = healthd_config_->screen_on(&props);
+ });
+ _hidl_cb(returned_result, screen_on);
+ return Void();
+}
+
+//
+// Subclass helpers / overrides
+//
+
+void Health::UpdateHealthInfo(HealthInfo* /* health_info */) {
+ /*
+ // Sample code for a subclass to implement this:
+ // If you need to modify values (e.g. batteryChargeTimeToFullNowSeconds), do it here.
+ health_info->batteryChargeTimeToFullNowSeconds = calculate_charge_time_seconds();
+
+ // If you need to call healthd_board_battery_update:
+ struct BatteryProperties props;
+ convertFromHealthInfo(health_info.legacy.legacy, &props);
+ healthd_board_battery_update(&props);
+ convertToHealthInfo(&props, health_info.legacy.legacy);
+ */
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/BinderHealth.h b/health/utils/libhealth2impl/include/health2impl/BinderHealth.h
new file mode 100644
index 0000000..1da5bd1
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/BinderHealth.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <healthd/healthd.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/HalHealthLoop.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// binderized health HAL implementation.
+class BinderHealth : public HalHealthLoop, public IHealth, public hidl_death_recipient {
+ public:
+ // |impl| should be the passthrough implementation.
+ BinderHealth(const std::string& name, const sp<IHealth>& impl);
+
+ // Methods from ::android::hardware::health::V2_0::IHealth follow.
+ Return<::android::hardware::health::V2_0::Result> registerCallback(
+ const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+ Return<::android::hardware::health::V2_0::Result> unregisterCallback(
+ const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+ Return<::android::hardware::health::V2_0::Result> update() override;
+ Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override {
+ return service()->getChargeCounter(_hidl_cb);
+ }
+ Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override {
+ return service()->getCurrentNow(_hidl_cb);
+ }
+ Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override {
+ return service()->getCurrentAverage(_hidl_cb);
+ }
+ Return<void> getCapacity(getCapacity_cb _hidl_cb) override {
+ return service()->getCapacity(_hidl_cb);
+ }
+ Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override {
+ return service()->getEnergyCounter(_hidl_cb);
+ }
+ Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override {
+ return service()->getChargeStatus(_hidl_cb);
+ }
+ Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override {
+ return service()->getStorageInfo(_hidl_cb);
+ }
+ Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override {
+ return service()->getDiskStats(_hidl_cb);
+ }
+ Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override {
+ return service()->getHealthInfo(_hidl_cb);
+ }
+
+ // Methods from ::android::hardware::health::V2_1::IHealth follow.
+ Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override {
+ return service()->getHealthConfig(_hidl_cb);
+ }
+ Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override {
+ return service()->getHealthInfo_2_1(_hidl_cb);
+ }
+ Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override {
+ return service()->shouldKeepScreenOn(_hidl_cb);
+ }
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override {
+ return service()->debug(fd, args);
+ }
+
+ // hidl_death_recipient implementation.
+ void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+
+ // Called by BinderHealthCallback.
+ void OnHealthInfoChanged(const HealthInfo& health_info) override;
+
+ protected:
+ void Init(struct healthd_config* config) override;
+ int PrepareToWait() override;
+ // A subclass may override this if it wants to handle binder events differently.
+ virtual void BinderEvent(uint32_t epevents);
+
+ private:
+ bool unregisterCallbackInternal(const sp<IBase>& callback);
+ int binder_fd_ = -1;
+ std::mutex callbacks_lock_;
+ std::vector<std::unique_ptr<Callback>> callbacks_;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/Callback.h b/health/utils/libhealth2impl/include/health2impl/Callback.h
new file mode 100644
index 0000000..a30480b
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/Callback.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hidl::base::V1_0::IBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// Wraps an IHealthInfoCallback.
+class Callback {
+ public:
+ virtual ~Callback() {}
+ virtual Return<void> Notify(const HealthInfo&) = 0;
+ virtual sp<IBase> Get() = 0;
+};
+
+class Callback_2_0 : public Callback {
+ public:
+ Callback_2_0(const sp<V2_0::IHealthInfoCallback>& callback) : callback_(callback) {}
+ Return<void> Notify(const HealthInfo& info) override {
+ return callback_->healthInfoChanged(info.legacy);
+ }
+ sp<IBase> Get() override { return callback_; }
+
+ private:
+ sp<V2_0::IHealthInfoCallback> callback_;
+};
+
+class Callback_2_1 : public Callback {
+ public:
+ Callback_2_1(const sp<IHealthInfoCallback>& callback) : callback_(callback) {}
+ Return<void> Notify(const HealthInfo& info) override {
+ return callback_->healthInfoChanged_2_1(info);
+ }
+ sp<IBase> Get() override { return callback_; }
+
+ private:
+ sp<IHealthInfoCallback> callback_;
+};
+
+inline std::unique_ptr<Callback> Wrap(const sp<V2_0::IHealthInfoCallback>& callback_2_0) {
+ auto callback_2_1 = IHealthInfoCallback::castFrom(callback_2_0).withDefault(nullptr);
+ if (callback_2_1) return std::make_unique<Callback_2_1>(callback_2_1);
+ return std::make_unique<Callback_2_0>(callback_2_0);
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
new file mode 100644
index 0000000..d9b5580
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health/HealthLoop.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// An implementation of HealthLoop for using a given health HAL. This is useful
+// for services that opens the passthrough implementation and starts the HealthLoop
+// to periodically poll data from the implementation.
+class HalHealthLoop : public HealthLoop {
+ public:
+ HalHealthLoop(const std::string& name, const sp<IHealth>& service)
+ : instance_name_(name), service_(service) {}
+
+ protected:
+ virtual void Init(struct healthd_config* config) override;
+ virtual void Heartbeat() override;
+ virtual int PrepareToWait() override;
+ virtual void ScheduleBatteryUpdate() override;
+
+ // HealthLoop periodically calls ScheduleBatteryUpdate, which calls
+ // OnHealthInfoChanged callback. A client can override this function to
+ // broadcast the health_info to interested listeners. By default, this
+ // adjust uevents / wakealarm periods.
+ virtual void OnHealthInfoChanged(const HealthInfo& health_info);
+
+ const std::string& instance_name() const { return instance_name_; }
+ const sp<IHealth>& service() const { return service_; }
+ bool charger_online() const { return charger_online_; }
+
+ // Helpers for subclasses to implement OnHealthInfoChanged.
+ void set_charger_online(const HealthInfo& health_info);
+
+ private:
+ const std::string& instance_name_;
+ sp<IHealth> service_;
+ bool charger_online_ = false;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/Health.h b/health/utils/libhealth2impl/include/health2impl/Health.h
new file mode 100644
index 0000000..853b0cd
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/Health.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <healthd/BatteryMonitor.h>
+#include <hidl/Status.h>
+
+#include <health2impl/Callback.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::base::V1_0::IBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+class Health : public IHealth {
+ public:
+ Health(std::unique_ptr<healthd_config>&& config);
+
+ // Methods from ::android::hardware::health::V2_0::IHealth follow.
+ Return<::android::hardware::health::V2_0::Result> registerCallback(
+ const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+ Return<::android::hardware::health::V2_0::Result> unregisterCallback(
+ const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+ Return<::android::hardware::health::V2_0::Result> update() override;
+ Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+ Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+ Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+ Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+ Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+ Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+ Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+ Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+ Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::health::V2_1::IHealth follow.
+ Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
+ Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
+ Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+ protected:
+ // A subclass can override this to modify any health info object before
+ // returning to clients. This is similar to healthd_board_battery_update().
+ // By default, it does nothing.
+ virtual void UpdateHealthInfo(HealthInfo* health_info);
+
+ private:
+ bool unregisterCallbackInternal(const sp<IBase>& callback);
+
+ BatteryMonitor battery_monitor_;
+ std::unique_ptr<healthd_config> healthd_config_;
+
+ std::mutex callbacks_lock_;
+ std::vector<std::unique_ptr<Callback>> callbacks_;
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace health
+} // namespace hardware
+} // namespace android
diff --git a/ir/1.0/vts/functional/Android.bp b/ir/1.0/vts/functional/Android.bp
index f5c9d61..f9edebd 100644
--- a/ir/1.0/vts/functional/Android.bp
+++ b/ir/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
static_libs: [
"android.hardware.ir@1.0",
],
- test_suites: ["general-tests"],
+ test_suites: ["general-tests", "vts-core"],
}
diff --git a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
index 5fd2dd4..a5dbdcc 100644
--- a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
+++ b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
#include <android/hardware/ir/1.0/IConsumerIr.h>
#include <android/hardware/ir/1.0/types.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
#include <algorithm>
using ::android::hardware::ir::V1_0::IConsumerIr;
@@ -31,26 +32,10 @@
using ::android::hardware::Return;
using ::android::sp;
-// Test environment for Ir
-class ConsumerIrHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static ConsumerIrHidlEnvironment* Instance() {
- static ConsumerIrHidlEnvironment* instance = new ConsumerIrHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IConsumerIr>(); }
- private:
- ConsumerIrHidlEnvironment() {}
-};
-
-// The main test class for IR HIDL HAL.
-class ConsumerIrHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ConsumerIrHidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- ir = ::testing::VtsHalHidlTargetTestBase::getService<IConsumerIr>(
- ConsumerIrHidlEnvironment::Instance()->getServiceName<IConsumerIr>());
+ ir = IConsumerIr::getService(GetParam());
ASSERT_NE(ir, nullptr);
}
@@ -60,7 +45,7 @@
};
// Test transmit() for the min and max frequency of every available range
-TEST_F(ConsumerIrHidlTest, TransmitTest) {
+TEST_P(ConsumerIrHidlTest, TransmitTest) {
bool success;
hidl_vec<ConsumerIrFreqRange> ranges;
auto cb = [&](bool s, hidl_vec<ConsumerIrFreqRange> v) {
@@ -84,7 +69,7 @@
}
// Test transmit() when called with invalid frequencies
-TEST_F(ConsumerIrHidlTest, BadFreqTest) {
+TEST_P(ConsumerIrHidlTest, BadFreqTest) {
uint32_t len = 16;
hidl_vec<int32_t> vec;
vec.resize(len);
@@ -92,11 +77,7 @@
EXPECT_FALSE(ir->transmit(-1, vec));
}
-int main(int argc, char **argv) {
- ::testing::AddGlobalTestEnvironment(ConsumerIrHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- ConsumerIrHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, ConsumerIrHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IConsumerIr::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/radio/1.5/Android.bp b/radio/1.5/Android.bp
new file mode 100644
index 0000000..06a2a6e
--- /dev/null
+++ b/radio/1.5/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.radio@1.5",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IRadio.hal",
+ "IRadioIndication.hal",
+ "IRadioResponse.hal",
+ ],
+ interfaces: [
+ "android.hardware.radio@1.0",
+ "android.hardware.radio@1.1",
+ "android.hardware.radio@1.2",
+ "android.hardware.radio@1.3",
+ "android.hardware.radio@1.4",
+ "android.hidl.base@1.0",
+ "android.hidl.safe_union@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
new file mode 100644
index 0000000..de20dd0
--- /dev/null
+++ b/radio/1.5/IRadio.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio@1.5;
+
+import @1.4::IRadio;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication.
+ */
+interface IRadio extends @1.4::IRadio {
+};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
new file mode 100644
index 0000000..d488404
--- /dev/null
+++ b/radio/1.5/IRadioIndication.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio@1.5;
+
+import @1.0::RadioIndicationType;
+import @1.4::IRadioIndication;
+
+/**
+ * Interface declaring unsolicited radio indications.
+ */
+interface IRadioIndication extends @1.4::IRadioIndication {
+};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
new file mode 100644
index 0000000..d4c4f76
--- /dev/null
+++ b/radio/1.5/IRadioResponse.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio@1.5;
+
+import @1.0::RadioResponseInfo;
+import @1.4::IRadioResponse;
+
+/**
+ * Interface declaring response functions to solicited radio requests.
+ */
+interface IRadioResponse extends @1.4::IRadioResponse {
+};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
new file mode 100644
index 0000000..a639a8d
--- /dev/null
+++ b/radio/1.5/types.hal
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio@1.5;
diff --git a/radio/1.5/vts/OWNERS b/radio/1.5/vts/OWNERS
new file mode 100644
index 0000000..3629a6c
--- /dev/null
+++ b/radio/1.5/vts/OWNERS
@@ -0,0 +1,10 @@
+# Telephony team
+refuhoo@google.com
+amitmahajan@google.com
+jackyu@google.com
+fionaxu@google.com
+# more to add
+
+# VTS team
+yuexima@google.com
+dshi@google.com
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
new file mode 100644
index 0000000..85c4f99
--- /dev/null
+++ b/radio/1.5/vts/functional/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalRadioV1_5TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "radio_hidl_hal_api.cpp",
+ "radio_hidl_hal_test.cpp",
+ "radio_response.cpp",
+ "radio_indication.cpp",
+ "VtsHalRadioV1_5TargetTest.cpp",
+ ],
+ static_libs: [
+ "RadioVtsTestUtilBase",
+ "android.hardware.radio@1.5",
+ "android.hardware.radio@1.4",
+ "android.hardware.radio@1.3",
+ "android.hardware.radio@1.2",
+ "android.hardware.radio@1.1",
+ "android.hardware.radio@1.0",
+ "android.hardware.radio.config@1.0",
+ "android.hardware.radio.config@1.1",
+ ],
+ header_libs: ["radio.util.header@1.0"],
+ test_suites: ["general-tests"]
+}
diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
new file mode 100644
index 0000000..b72febd
--- /dev/null
+++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ RadioHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
new file mode 100644
index 0000000..b86fa5f
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
new file mode 100644
index 0000000..a5d236d
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+void RadioHidlTest_v1_5::SetUp() {
+ radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::V1_5::IRadio>(
+ RadioHidlEnvironment::Instance()
+ ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+ hidl_string(RADIO_SERVICE_NAME)));
+ if (radio_v1_5 == NULL) {
+ sleep(60);
+ radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::V1_5::IRadio>(
+ RadioHidlEnvironment::Instance()
+ ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+ hidl_string(RADIO_SERVICE_NAME)));
+ }
+ ASSERT_NE(nullptr, radio_v1_5.get());
+
+ radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this);
+ ASSERT_NE(nullptr, radioRsp_v1_5.get());
+
+ count_ = 0;
+
+ radioInd_v1_5 = new (std::nothrow) RadioIndication_v1_5(*this);
+ ASSERT_NE(nullptr, radioInd_v1_5.get());
+
+ radio_v1_5->setResponseFunctions(radioRsp_v1_5, radioInd_v1_5);
+
+ updateSimCardStatus();
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
+ ::testing::VtsHalHidlTargetTestBase::getService<
+ ::android::hardware::radio::config::V1_1::IRadioConfig>();
+
+ /* Enforce Vts tesing with RadioConfig is existed. */
+ ASSERT_NE(nullptr, radioConfig.get());
+
+ /* Enforce Vts Testing with Sim Status Present only. */
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioHidlTest_v1_5::notify(int receivedSerial) {
+ std::unique_lock<std::mutex> lock(mtx_);
+ if (serial == receivedSerial) {
+ count_++;
+ cv_.notify_one();
+ }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioHidlTest_v1_5::wait() {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ std::cv_status status = std::cv_status::no_timeout;
+ auto now = std::chrono::system_clock::now();
+ while (count_ == 0) {
+ status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+ if (status == std::cv_status::timeout) {
+ return status;
+ }
+ }
+ count_--;
+ return status;
+}
+
+void RadioHidlTest_v1_5::updateSimCardStatus() {
+ serial = GetRandomSerialNumber();
+ radio_v1_5->getIccCardStatus(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
new file mode 100644
index 0000000..799702b
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+
+#include <android/hardware/radio/1.5/IRadio.h>
+#include <android/hardware/radio/1.5/IRadioIndication.h>
+#include <android/hardware/radio/1.5/IRadioResponse.h>
+#include <android/hardware/radio/1.5/types.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::V1_5;
+using namespace ::android::hardware::radio::V1_4;
+using namespace ::android::hardware::radio::V1_3;
+using namespace ::android::hardware::radio::V1_2;
+using namespace ::android::hardware::radio::V1_1;
+using namespace ::android::hardware::radio::V1_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 75
+#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
+#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
+
+#define RADIO_SERVICE_NAME "slot1"
+
+class RadioHidlTest_v1_5;
+extern ::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+/* Callback class for radio respons v1_5 */
+class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse {
+ protected:
+ RadioHidlTest_v1_5& parent_v1_5;
+
+ public:
+ hidl_vec<RadioBandMode> radioBandModes;
+
+ RadioResponseInfo rspInfo;
+
+ // Call
+ hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
+
+ // Modem
+ bool isModemEnabled;
+ bool enableModemResponseToggle;
+
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmapResponse;
+
+ // Data
+ ::android::hardware::radio::V1_4::DataRegStateResult dataRegResp;
+
+ // SimLock status
+ ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp;
+ ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp;
+
+ RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+ virtual ~RadioResponse_v1_5() = default;
+
+ Return<void> getIccCardStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::CardStatus& cardStatus);
+
+ Return<void> supplyIccPinForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyIccPukForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> changeIccPinForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> changeIccPin2ForAppResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
+ int32_t remainingRetries);
+
+ Return<void> getCurrentCallsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
+
+ Return<void> dialResponse(const RadioResponseInfo& info);
+
+ Return<void> getIMSIForAppResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& imsi);
+
+ Return<void> hangupConnectionResponse(const RadioResponseInfo& info);
+
+ Return<void> hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info);
+
+ Return<void> hangupForegroundResumeBackgroundResponse(const RadioResponseInfo& info);
+
+ Return<void> switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info);
+
+ Return<void> conferenceResponse(const RadioResponseInfo& info);
+
+ Return<void> rejectCallResponse(const RadioResponseInfo& info);
+
+ Return<void> getLastCallFailCauseResponse(const RadioResponseInfo& info,
+ const LastCallFailCauseInfo& failCauseInfo);
+
+ Return<void> getSignalStrengthResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::SignalStrength& sigStrength);
+
+ Return<void> getVoiceRegistrationStateResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse);
+
+ Return<void> getDataRegistrationStateResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse);
+
+ Return<void> getOperatorResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& longName,
+ const ::android::hardware::hidl_string& shortName,
+ const ::android::hardware::hidl_string& numeric);
+
+ Return<void> setRadioPowerResponse(const RadioResponseInfo& info);
+
+ Return<void> sendDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> sendSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> sendSMSExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> setupDataCallResponse(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_0::SetupDataCallResult& dcResponse);
+
+ Return<void> iccIOForAppResponse(const RadioResponseInfo& info, const IccIoResult& iccIo);
+
+ Return<void> sendUssdResponse(const RadioResponseInfo& info);
+
+ Return<void> cancelPendingUssdResponse(const RadioResponseInfo& info);
+
+ Return<void> getClirResponse(const RadioResponseInfo& info, int32_t n, int32_t m);
+
+ Return<void> setClirResponse(const RadioResponseInfo& info);
+
+ Return<void> getCallForwardStatusResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<CallForwardInfo>& call_forwardInfos);
+
+ Return<void> setCallForwardResponse(const RadioResponseInfo& info);
+
+ Return<void> getCallWaitingResponse(const RadioResponseInfo& info, bool enable,
+ int32_t serviceClass);
+
+ Return<void> setCallWaitingResponse(const RadioResponseInfo& info);
+
+ Return<void> acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info);
+
+ Return<void> acceptCallResponse(const RadioResponseInfo& info);
+
+ Return<void> deactivateDataCallResponse(const RadioResponseInfo& info);
+
+ Return<void> getFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t response);
+
+ Return<void> setFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t retry);
+
+ Return<void> setBarringPasswordResponse(const RadioResponseInfo& info);
+
+ Return<void> getNetworkSelectionModeResponse(const RadioResponseInfo& info, bool manual);
+
+ Return<void> setNetworkSelectionModeAutomaticResponse(const RadioResponseInfo& info);
+
+ Return<void> setNetworkSelectionModeManualResponse(const RadioResponseInfo& info);
+
+ Return<void> getAvailableNetworksResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<OperatorInfo>& networkInfos);
+
+ Return<void> startDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> stopDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> getBasebandVersionResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& version);
+
+ Return<void> separateConnectionResponse(const RadioResponseInfo& info);
+
+ Return<void> setMuteResponse(const RadioResponseInfo& info);
+
+ Return<void> getMuteResponse(const RadioResponseInfo& info, bool enable);
+
+ Return<void> getClipResponse(const RadioResponseInfo& info, ClipStatus status);
+
+ Return<void> getDataCallListResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ android::hardware::radio::V1_0::SetupDataCallResult>& dcResponse);
+
+ Return<void> sendOemRilRequestRawResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<uint8_t>& data);
+
+ Return<void> sendOemRilRequestStringsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
+
+ Return<void> setSuppServiceNotificationsResponse(const RadioResponseInfo& info);
+
+ Return<void> writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index);
+
+ Return<void> deleteSmsOnSimResponse(const RadioResponseInfo& info);
+
+ Return<void> setBandModeResponse(const RadioResponseInfo& info);
+
+ Return<void> getAvailableBandModesResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<RadioBandMode>& bandModes);
+
+ Return<void> sendEnvelopeResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& commandResponse);
+
+ Return<void> sendTerminalResponseToSimResponse(const RadioResponseInfo& info);
+
+ Return<void> handleStkCallSetupRequestFromSimResponse(const RadioResponseInfo& info);
+
+ Return<void> explicitCallTransferResponse(const RadioResponseInfo& info);
+
+ Return<void> setPreferredNetworkTypeResponse(const RadioResponseInfo& info);
+
+ Return<void> getPreferredNetworkTypeResponse(const RadioResponseInfo& info,
+ PreferredNetworkType nwType);
+
+ Return<void> getNeighboringCidsResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<NeighboringCell>& cells);
+
+ Return<void> setLocationUpdatesResponse(const RadioResponseInfo& info);
+
+ Return<void> setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info);
+
+ Return<void> setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info);
+
+ Return<void> getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
+ CdmaRoamingType type);
+
+ Return<void> setTTYModeResponse(const RadioResponseInfo& info);
+
+ Return<void> getTTYModeResponse(const RadioResponseInfo& info, TtyMode mode);
+
+ Return<void> setPreferredVoicePrivacyResponse(const RadioResponseInfo& info);
+
+ Return<void> getPreferredVoicePrivacyResponse(const RadioResponseInfo& info, bool enable);
+
+ Return<void> sendCDMAFeatureCodeResponse(const RadioResponseInfo& info);
+
+ Return<void> sendBurstDtmfResponse(const RadioResponseInfo& info);
+
+ Return<void> sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info);
+
+ Return<void> getGsmBroadcastConfigResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& configs);
+
+ Return<void> setGsmBroadcastConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> setGsmBroadcastActivationResponse(const RadioResponseInfo& info);
+
+ Return<void> getCdmaBroadcastConfigResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& configs);
+
+ Return<void> setCdmaBroadcastConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> setCdmaBroadcastActivationResponse(const RadioResponseInfo& info);
+
+ Return<void> getCDMASubscriptionResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& mdn,
+ const ::android::hardware::hidl_string& hSid,
+ const ::android::hardware::hidl_string& hNid,
+ const ::android::hardware::hidl_string& min,
+ const ::android::hardware::hidl_string& prl);
+
+ Return<void> writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index);
+
+ Return<void> deleteSmsOnRuimResponse(const RadioResponseInfo& info);
+
+ Return<void> getDeviceIdentityResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& imei,
+ const ::android::hardware::hidl_string& imeisv,
+ const ::android::hardware::hidl_string& esn,
+ const ::android::hardware::hidl_string& meid);
+
+ Return<void> exitEmergencyCallbackModeResponse(const RadioResponseInfo& info);
+
+ Return<void> getSmscAddressResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& smsc);
+
+ Return<void> setSmscAddressResponse(const RadioResponseInfo& info);
+
+ Return<void> reportSmsMemoryStatusResponse(const RadioResponseInfo& info);
+
+ Return<void> reportStkServiceIsRunningResponse(const RadioResponseInfo& info);
+
+ Return<void> getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info,
+ CdmaSubscriptionSource source);
+
+ Return<void> requestIsimAuthenticationResponse(
+ const RadioResponseInfo& info, const ::android::hardware::hidl_string& response);
+
+ Return<void> acknowledgeIncomingGsmSmsWithPduResponse(const RadioResponseInfo& info);
+
+ Return<void> sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
+ const IccIoResult& iccIo);
+
+ Return<void> getVoiceRadioTechnologyResponse(
+ const RadioResponseInfo& info, ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+ Return<void> getCellInfoListResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+ cellInfo);
+
+ Return<void> setCellInfoListRateResponse(const RadioResponseInfo& info);
+
+ Return<void> setInitialAttachApnResponse(const RadioResponseInfo& info);
+
+ Return<void> getImsRegistrationStateResponse(const RadioResponseInfo& info, bool isRegistered,
+ RadioTechnologyFamily ratFamily);
+
+ Return<void> sendImsSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+ Return<void> iccTransmitApduBasicChannelResponse(const RadioResponseInfo& info,
+ const IccIoResult& result);
+
+ Return<void> iccOpenLogicalChannelResponse(
+ const RadioResponseInfo& info, int32_t channelId,
+ const ::android::hardware::hidl_vec<int8_t>& selectResponse);
+
+ Return<void> iccCloseLogicalChannelResponse(const RadioResponseInfo& info);
+
+ Return<void> iccTransmitApduLogicalChannelResponse(const RadioResponseInfo& info,
+ const IccIoResult& result);
+
+ Return<void> nvReadItemResponse(const RadioResponseInfo& info,
+ const ::android::hardware::hidl_string& result);
+
+ Return<void> nvWriteItemResponse(const RadioResponseInfo& info);
+
+ Return<void> nvWriteCdmaPrlResponse(const RadioResponseInfo& info);
+
+ Return<void> nvResetConfigResponse(const RadioResponseInfo& info);
+
+ Return<void> setUiccSubscriptionResponse(const RadioResponseInfo& info);
+
+ Return<void> setDataAllowedResponse(const RadioResponseInfo& info);
+
+ Return<void> getHardwareConfigResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<HardwareConfig>& config);
+
+ Return<void> requestIccSimAuthenticationResponse(const RadioResponseInfo& info,
+ const IccIoResult& result);
+
+ Return<void> setDataProfileResponse(const RadioResponseInfo& info);
+
+ Return<void> requestShutdownResponse(const RadioResponseInfo& info);
+
+ Return<void> getRadioCapabilityResponse(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_0::RadioCapability& rc);
+
+ Return<void> setRadioCapabilityResponse(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_0::RadioCapability& rc);
+
+ Return<void> startLceServiceResponse(const RadioResponseInfo& info,
+ const LceStatusInfo& statusInfo);
+
+ Return<void> stopLceServiceResponse(const RadioResponseInfo& info,
+ const LceStatusInfo& statusInfo);
+
+ Return<void> pullLceDataResponse(const RadioResponseInfo& info, const LceDataInfo& lceInfo);
+
+ Return<void> getModemActivityInfoResponse(const RadioResponseInfo& info,
+ const ActivityStatsInfo& activityInfo);
+
+ Return<void> setAllowedCarriersResponse(const RadioResponseInfo& info, int32_t numAllowed);
+
+ Return<void> getAllowedCarriersResponse(const RadioResponseInfo& info, bool allAllowed,
+ const CarrierRestrictions& carriers);
+
+ Return<void> sendDeviceStateResponse(const RadioResponseInfo& info);
+
+ Return<void> setIndicationFilterResponse(const RadioResponseInfo& info);
+
+ Return<void> setSimCardPowerResponse(const RadioResponseInfo& info);
+
+ Return<void> acknowledgeRequest(int32_t serial);
+
+ /* 1.1 Api */
+ Return<void> setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info);
+
+ Return<void> setSimCardPowerResponse_1_1(const RadioResponseInfo& info);
+
+ Return<void> startNetworkScanResponse(const RadioResponseInfo& info);
+
+ Return<void> stopNetworkScanResponse(const RadioResponseInfo& info);
+
+ Return<void> startKeepaliveResponse(const RadioResponseInfo& info,
+ const KeepaliveStatus& status);
+
+ Return<void> stopKeepaliveResponse(const RadioResponseInfo& info);
+
+ /* 1.2 Api */
+ Return<void> setSignalStrengthReportingCriteriaResponse(const RadioResponseInfo& info);
+
+ Return<void> setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info);
+
+ Return<void> getIccCardStatusResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::CardStatus& card_status);
+
+ Return<void> getCurrentCallsResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls);
+
+ Return<void> getSignalStrengthResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::SignalStrength& sig_strength);
+
+ Return<void> getSignalStrengthResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::SignalStrength& sig_strength);
+
+ Return<void> getCellInfoListResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+ cellInfo);
+
+ Return<void> getVoiceRegistrationStateResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse);
+
+ Return<void> getDataRegistrationStateResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse);
+
+ /* 1.3 Api */
+ Return<void> setSystemSelectionChannelsResponse(const RadioResponseInfo& info);
+
+ Return<void> enableModemResponse(const RadioResponseInfo& info);
+
+ Return<void> getModemStackStatusResponse(const RadioResponseInfo& info, const bool enabled);
+
+ /* 1.4 Api */
+ Return<void> emergencyDialResponse(const RadioResponseInfo& info);
+
+ Return<void> startNetworkScanResponse_1_4(const RadioResponseInfo& info);
+
+ Return<void> getCellInfoListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+ cellInfo);
+
+ Return<void> getDataRegistrationStateResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse);
+
+ Return<void> getIccCardStatusResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::CardStatus& card_status);
+
+ Return<void> getPreferredNetworkTypeBitmapResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_bitfield<
+ ::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmap);
+
+ Return<void> setPreferredNetworkTypeBitmapResponse(const RadioResponseInfo& info);
+
+ Return<void> getDataCallListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::SetupDataCallResult>& dcResponse);
+
+ Return<void> setupDataCallResponse_1_4(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+
+ Return<void> setAllowedCarriersResponse_1_4(const RadioResponseInfo& info);
+
+ Return<void> getAllowedCarriersResponse_1_4(const RadioResponseInfo& info,
+ const CarrierRestrictionsWithPriority& carriers,
+ SimLockMultiSimPolicy multiSimPolicy);
+};
+
+/* Callback class for radio indication */
+class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndication {
+ protected:
+ RadioHidlTest_v1_5& parent_v1_5;
+
+ public:
+ RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+ virtual ~RadioIndication_v1_5() = default;
+
+ /* 1.4 Api */
+ Return<void> currentEmergencyNumberList(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<EmergencyNumber>& emergencyNumberList);
+
+ Return<void> cellInfoList_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+ records);
+
+ Return<void> networkScanResult_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_4::NetworkScanResult& result);
+
+ Return<void> currentPhysicalChannelConfigs_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::PhysicalChannelConfig>& configs);
+
+ Return<void> dataCallListChanged_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ android::hardware::radio::V1_4::SetupDataCallResult>& dcList);
+
+ /* 1.2 Api */
+ Return<void> networkScanResult_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::NetworkScanResult& result);
+
+ Return<void> cellInfoList_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+ records);
+
+ Return<void> currentLinkCapacityEstimate(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce);
+
+ Return<void> currentPhysicalChannelConfigs(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::PhysicalChannelConfig>& configs);
+
+ Return<void> currentSignalStrength_1_2(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_2::SignalStrength& signalStrength);
+
+ Return<void> currentSignalStrength_1_4(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_4::SignalStrength& signalStrength);
+
+ /* 1.1 Api */
+ Return<void> carrierInfoForImsiEncryption(RadioIndicationType info);
+
+ Return<void> networkScanResult(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_1::NetworkScanResult& result);
+
+ Return<void> keepaliveStatus(RadioIndicationType type, const KeepaliveStatus& status);
+
+ /* 1.0 Api */
+ Return<void> radioStateChanged(RadioIndicationType type, RadioState radioState);
+
+ Return<void> callStateChanged(RadioIndicationType type);
+
+ Return<void> networkStateChanged(RadioIndicationType type);
+
+ Return<void> newSms(RadioIndicationType type,
+ const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+ Return<void> newSmsStatusReport(RadioIndicationType type,
+ const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+ Return<void> newSmsOnSim(RadioIndicationType type, int32_t recordNumber);
+
+ Return<void> onUssd(RadioIndicationType type, UssdModeType modeType,
+ const ::android::hardware::hidl_string& msg);
+
+ Return<void> nitzTimeReceived(RadioIndicationType type,
+ const ::android::hardware::hidl_string& nitzTime,
+ uint64_t receivedTime);
+
+ Return<void> currentSignalStrength(
+ RadioIndicationType type,
+ const ::android::hardware::radio::V1_0::SignalStrength& signalStrength);
+
+ Return<void> dataCallListChanged(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<
+ android::hardware::radio::V1_0::SetupDataCallResult>& dcList);
+
+ Return<void> suppSvcNotify(RadioIndicationType type, const SuppSvcNotification& suppSvc);
+
+ Return<void> stkSessionEnd(RadioIndicationType type);
+
+ Return<void> stkProactiveCommand(RadioIndicationType type,
+ const ::android::hardware::hidl_string& cmd);
+
+ Return<void> stkEventNotify(RadioIndicationType type,
+ const ::android::hardware::hidl_string& cmd);
+
+ Return<void> stkCallSetup(RadioIndicationType type, int64_t timeout);
+
+ Return<void> simSmsStorageFull(RadioIndicationType type);
+
+ Return<void> simRefresh(RadioIndicationType type, const SimRefreshResult& refreshResult);
+
+ Return<void> callRing(RadioIndicationType type, bool isGsm, const CdmaSignalInfoRecord& record);
+
+ Return<void> simStatusChanged(RadioIndicationType type);
+
+ Return<void> cdmaNewSms(RadioIndicationType type, const CdmaSmsMessage& msg);
+
+ Return<void> newBroadcastSms(RadioIndicationType type,
+ const ::android::hardware::hidl_vec<uint8_t>& data);
+
+ Return<void> cdmaRuimSmsStorageFull(RadioIndicationType type);
+
+ Return<void> restrictedStateChanged(RadioIndicationType type, PhoneRestrictedState state);
+
+ Return<void> enterEmergencyCallbackMode(RadioIndicationType type);
+
+ Return<void> cdmaCallWaiting(RadioIndicationType type,
+ const CdmaCallWaiting& callWaitingRecord);
+
+ Return<void> cdmaOtaProvisionStatus(RadioIndicationType type, CdmaOtaProvisionStatus status);
+
+ Return<void> cdmaInfoRec(RadioIndicationType type, const CdmaInformationRecords& records);
+
+ Return<void> indicateRingbackTone(RadioIndicationType type, bool start);
+
+ Return<void> resendIncallMute(RadioIndicationType type);
+
+ Return<void> cdmaSubscriptionSourceChanged(RadioIndicationType type,
+ CdmaSubscriptionSource cdmaSource);
+
+ Return<void> cdmaPrlChanged(RadioIndicationType type, int32_t version);
+
+ Return<void> exitEmergencyCallbackMode(RadioIndicationType type);
+
+ Return<void> rilConnected(RadioIndicationType type);
+
+ Return<void> voiceRadioTechChanged(RadioIndicationType type,
+ ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+ Return<void> cellInfoList(
+ RadioIndicationType type,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+ records);
+
+ Return<void> imsNetworkStateChanged(RadioIndicationType type);
+
+ Return<void> subscriptionStatusChanged(RadioIndicationType type, bool activate);
+
+ Return<void> srvccStateNotify(RadioIndicationType type, SrvccState state);
+
+ Return<void> hardwareConfigChanged(
+ RadioIndicationType type, const ::android::hardware::hidl_vec<HardwareConfig>& configs);
+
+ Return<void> radioCapabilityIndication(
+ RadioIndicationType type, const android::hardware::radio::V1_0::RadioCapability& rc);
+
+ Return<void> onSupplementaryServiceIndication(RadioIndicationType type,
+ const StkCcUnsolSsResult& ss);
+
+ Return<void> stkCallControlAlphaNotify(RadioIndicationType type,
+ const ::android::hardware::hidl_string& alpha);
+
+ Return<void> lceData(RadioIndicationType type, const LceDataInfo& lce);
+
+ Return<void> pcoData(RadioIndicationType type, const PcoDataInfo& pco);
+
+ Return<void> modemReset(RadioIndicationType type,
+ const ::android::hardware::hidl_string& reason);
+};
+
+// Test environment for Radio HIDL HAL.
+class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static RadioHidlEnvironment* Instance() {
+ static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
+ return instance;
+ }
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::radio::V1_5::IRadio>();
+ }
+
+ private:
+ RadioHidlEnvironment() {}
+};
+
+// The main test class for Radio HIDL.
+class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int count_;
+
+ /* Serial number for radio request */
+ int serial;
+
+ /* Clear Potential Established Calls */
+ void clearPotentialEstablishedCalls();
+
+ /* Update Sim Card Status */
+ void updateSimCardStatus();
+
+ public:
+ virtual void SetUp() override;
+
+ /* Used as a mechanism to inform the test about data/event callback */
+ void notify(int receivedSerial);
+
+ /* Test code calls this function to wait for response */
+ std::cv_status wait();
+
+ /* radio service handle */
+ sp<::android::hardware::radio::V1_5::IRadio> radio_v1_5;
+
+ /* radio response handle */
+ sp<RadioResponse_v1_5> radioRsp_v1_5;
+
+ /* radio indication handle */
+ sp<RadioIndication_v1_5> radioInd_v1_5;
+};
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
new file mode 100644
index 0000000..b63b745
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.4 Apis */
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::PhysicalChannelConfig>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_4::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentEmergencyNumberList(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<EmergencyNumber>& /*emergencyNumberList*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<android::hardware::radio::V1_4::SetupDataCallResult>&
+ /*dcList*/) {
+ return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioIndication_v1_5::networkScanResult_1_2(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_2(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentLinkCapacityEstimate(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_2(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_4(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_4::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioIndication_v1_5::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::keepaliveStatus(RadioIndicationType /*type*/,
+ const KeepaliveStatus& /*status*/) {
+ return Void();
+}
+
+/* 1.0 Apis */
+Return<void> RadioIndication_v1_5::radioStateChanged(RadioIndicationType /*type*/,
+ RadioState /*radioState*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::callStateChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkStateChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSms(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsStatusReport(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsOnSim(RadioIndicationType /*type*/,
+ int32_t /*recordNumber*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/,
+ const ::android::hardware::hidl_string& /*msg*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::nitzTimeReceived(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/,
+ uint64_t /*receivedTime*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+ /*dcList*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::suppSvcNotify(RadioIndicationType /*type*/,
+ const SuppSvcNotification& /*suppSvc*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkSessionEnd(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkProactiveCommand(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkEventNotify(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_string& /*cmd*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::simSmsStorageFull(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::simRefresh(RadioIndicationType /*type*/,
+ const SimRefreshResult& /*refreshResult*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::callRing(RadioIndicationType /*type*/, bool /*isGsm*/,
+ const CdmaSignalInfoRecord& /*record*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::simStatusChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaNewSms(RadioIndicationType /*type*/,
+ const CdmaSmsMessage& /*msg*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::newBroadcastSms(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::restrictedStateChanged(RadioIndicationType /*type*/,
+ PhoneRestrictedState /*state*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::enterEmergencyCallbackMode(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaCallWaiting(RadioIndicationType /*type*/,
+ const CdmaCallWaiting& /*callWaitingRecord*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaOtaProvisionStatus(RadioIndicationType /*type*/,
+ CdmaOtaProvisionStatus /*status*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaInfoRec(RadioIndicationType /*type*/,
+ const CdmaInformationRecords& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::indicateRingbackTone(RadioIndicationType /*type*/,
+ bool /*start*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::resendIncallMute(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaSubscriptionSourceChanged(
+ RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaPrlChanged(RadioIndicationType /*type*/,
+ int32_t /*version*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::exitEmergencyCallbackMode(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::rilConnected(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::voiceRadioTechChanged(
+ RadioIndicationType /*type*/, ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_0::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::imsNetworkStateChanged(RadioIndicationType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::subscriptionStatusChanged(RadioIndicationType /*type*/,
+ bool /*activate*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::srvccStateNotify(RadioIndicationType /*type*/,
+ SrvccState /*state*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::hardwareConfigChanged(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_vec<HardwareConfig>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::radioCapabilityIndication(
+ RadioIndicationType /*type*/,
+ const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::onSupplementaryServiceIndication(
+ RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallControlAlphaNotify(
+ RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::lceData(RadioIndicationType /*type*/,
+ const LceDataInfo& /*lce*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::pcoData(RadioIndicationType /*type*/,
+ const PcoDataInfo& /*pco*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/,
+ const ::android::hardware::hidl_string& /*reason*/) {
+ return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
new file mode 100644
index 0000000..1e5cc47
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -0,0 +1,887 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyNetworkDepersonalizationResponse(
+ const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::dialResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIMSIForAppResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupConnectionResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupWaitingOrBackgroundResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupForegroundResumeBackgroundResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::switchWaitingOrHoldingAndActiveResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::conferenceResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::rejectCallResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getLastCallFailCauseResponse(
+ const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getOperatorResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*longName*/,
+ const ::android::hardware::hidl_string& /*shortName*/,
+ const ::android::hardware::hidl_string& /*numeric*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSmsResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse(
+ const RadioResponseInfo& /*info*/,
+ const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccIOForAppResponse(const RadioResponseInfo& /*info*/,
+ const IccIoResult& /*iccIo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendUssdResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/,
+ int32_t /*m*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setClirResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallForwardStatusResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>&
+ /*callForwardInfos*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallForwardResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallWaitingResponse(const RadioResponseInfo& /*info*/,
+ bool /*enable*/, int32_t /*serviceClass*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallWaitingResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingGsmSmsResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acceptCallResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::deactivateDataCallResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*response*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*retry*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/,
+ bool /*manual*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeAutomaticResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeManualResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableNetworksResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getBasebandVersionResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::separateConnectionResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setMuteResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getMuteResponse(const RadioResponseInfo& /*info*/,
+ bool /*enable*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClipResponse(const RadioResponseInfo& /*info*/,
+ ClipStatus /*status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+ /*dcResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestRawResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestStringsResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSuppServiceNotificationsResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToSimResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*index*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBandModeResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableBandModesResponse(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) {
+ rspInfo = info;
+ radioBandModes = bandModes;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_string& /*commandResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendTerminalResponseToSimResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::handleStkCallSetupRequestFromSimResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/,
+ PreferredNetworkType /*nw_type*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNeighboringCidsResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaSubscriptionSourceResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaRoamingPreferenceResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/,
+ CdmaRoamingType /*type*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setTTYModeResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getTTYModeResponse(const RadioResponseInfo& /*info*/,
+ TtyMode /*mode*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredVoicePrivacyResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/,
+ bool /*enable*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingCdmaSmsResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getGsmBroadcastConfigResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastActivationResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaBroadcastConfigResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastActivationResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCDMASubscriptionResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*mdn*/,
+ const ::android::hardware::hidl_string& /*hSid*/,
+ const ::android::hardware::hidl_string& /*hNid*/,
+ const ::android::hardware::hidl_string& /*min*/,
+ const ::android::hardware::hidl_string& /*prl*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/,
+ uint32_t /*index*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDeviceIdentityResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imei*/,
+ const ::android::hardware::hidl_string& /*imeisv*/,
+ const ::android::hardware::hidl_string& /*esn*/,
+ const ::android::hardware::hidl_string& /*meid*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::exitEmergencyCallbackModeResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSmscAddressResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSmscAddressResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportStkServiceIsRunningResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaSubscriptionSourceResponse(
+ const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIsimAuthenticationResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeIncomingGsmSmsWithPduResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/,
+ const IccIoResult& /*iccIo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRadioTechnologyResponse(
+ const RadioResponseInfo& /*info*/,
+ ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setInitialAttachApnResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getImsRegistrationStateResponse(
+ const RadioResponseInfo& /*info*/, bool /*isRegistered*/,
+ RadioTechnologyFamily /*ratFamily*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendImsSmsResponse(const RadioResponseInfo& /*info*/,
+ const SendSmsResult& /*sms*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduBasicChannelResponse(
+ const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccOpenLogicalChannelResponse(
+ const RadioResponseInfo& /*info*/, int32_t /*channelId*/,
+ const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduLogicalChannelResponse(
+ const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvReadItemResponse(
+ const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteItemResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvResetConfigResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataAllowedResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getHardwareConfigResponse(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIccSimAuthenticationResponse(
+ const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataProfileResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestShutdownResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getRadioCapabilityResponse(
+ const RadioResponseInfo& /*info*/,
+ const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioCapabilityResponse(
+ const RadioResponseInfo& /*info*/,
+ const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startLceServiceResponse(const RadioResponseInfo& /*info*/,
+ const LceStatusInfo& /*statusInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopLceServiceResponse(const RadioResponseInfo& /*info*/,
+ const LceStatusInfo& /*statusInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::pullLceDataResponse(const RadioResponseInfo& /*info*/,
+ const LceDataInfo& /*lceInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemActivityInfoResponse(
+ const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/,
+ int32_t /*numAllowed*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse(
+ const RadioResponseInfo& /*info*/, bool /*allAllowed*/,
+ const CarrierRestrictions& /*carriers*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setIndicationFilterResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeRequest(int32_t /*serial*/) {
+ return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioResponse_v1_5::setCarrierInfoForImsiEncryptionResponse(
+ const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopNetworkScanResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startKeepaliveResponse(const RadioResponseInfo& /*info*/,
+ const KeepaliveStatus& /*status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) {
+ return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_2(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
+ rspInfo = info;
+ currentCalls = calls;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_2(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) {
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_2(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_2(
+ const RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) {
+ return Void();
+}
+
+/* 1.3 Apis */
+Return<void> RadioResponse_v1_5::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::enableModemResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemStackStatusResponse(const RadioResponseInfo& info,
+ const bool enabled) {
+ rspInfo = info;
+ isModemEnabled = enabled;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+/* 1.4 Apis */
+Return<void> RadioResponse_v1_5::emergencyDialResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse_1_4(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) {
+ rspInfo = info;
+ dataRegResp = dataRegResponse;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<
+ ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_4::CardStatus& card_status) {
+ rspInfo = info;
+ cardStatus = card_status;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeBitmapResponse(
+ const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield<
+ ::android::hardware::radio::V1_4::RadioAccessFamily>
+ networkTypeBitmap) {
+ rspInfo = info;
+ networkTypeBitmapResponse = networkTypeBitmap;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeBitmapResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse_1_4(
+ const RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>&
+ /*dcResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse_1_4(
+ const RadioResponseInfo& info,
+ const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse_1_4(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse_1_4(
+ const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers,
+ SimLockMultiSimPolicy multiSimPolicy) {
+ rspInfo = info;
+ carrierRestrictionsResp = carriers;
+ multiSimPolicyResp = multiSimPolicy;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
new file mode 100644
index 0000000..c13eaf2
--- /dev/null
+++ b/sensors/2.0/multihal/Android.bp
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "android.hardware.sensors@2.0-multihal-defaults",
+ header_libs: [
+ "android.hardware.sensors@2.0-multihal.header",
+ ],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "liblog",
+ "libpower",
+ "libutils",
+ ],
+ cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
+}
+
+cc_binary {
+ name: "android.hardware.sensors@2.0-service.multihal",
+ defaults: [
+ "hidl_defaults",
+ "android.hardware.sensors@2.0-multihal-defaults",
+ ],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "HalProxy.cpp",
+ "ScopedWakelock.cpp",
+ ],
+ init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
+ vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
+}
+
+cc_library_headers {
+ name: "android.hardware.sensors@2.0-multihal.header",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
+// The below targets should only be used for testing.
+cc_test_library {
+ name: "android.hardware.sensors@2.0-HalProxy",
+ defaults: ["android.hardware.sensors@2.0-multihal-defaults"],
+ vendor_available: true,
+ srcs: [
+ "HalProxy.cpp",
+ "ScopedWakelock.cpp",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.sensors@2.0-multihal.header",
+ ],
+ shared_libs: [
+ "libutils",
+ ],
+}
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
new file mode 100644
index 0000000..49c5a0d
--- /dev/null
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HalProxy.h"
+
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+
+#include <android-base/file.h>
+#include "hardware_legacy/power.h"
+
+#include <dlfcn.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <functional>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
+using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
+
+typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
+
+static constexpr int32_t kBitsAfterSubHalIndex = 24;
+
+/**
+ * Set the subhal index as first byte of sensor handle and return this modified version.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
+ *
+ * @return The modified sensor handle.
+ */
+int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
+ return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
+}
+
+/**
+ * Extract the subHalIndex from sensorHandle.
+ *
+ * @param sensorHandle The sensorHandle to extract from.
+ *
+ * @return The subhal index.
+ */
+size_t extractSubHalIndex(int32_t sensorHandle) {
+ return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
+}
+
+/**
+ * Convert nanoseconds to milliseconds.
+ *
+ * @param nanos The nanoseconds input.
+ *
+ * @return The milliseconds count.
+ */
+int64_t msFromNs(int64_t nanos) {
+ constexpr int64_t nanosecondsInAMillsecond = 1000000;
+ return nanos / nanosecondsInAMillsecond;
+}
+
+HalProxy::HalProxy() {
+ const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
+ initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+ init();
+}
+
+HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
+ init();
+}
+
+HalProxy::~HalProxy() {
+ stopThreads();
+}
+
+Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& iter : mSensors) {
+ sensors.push_back(iter.second);
+ }
+ _hidl_cb(sensors);
+ return Void();
+}
+
+Return<Result> HalProxy::setOperationMode(OperationMode mode) {
+ Result result = Result::OK;
+ size_t subHalIndex;
+ for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+ ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+ result = subHal->setOperationMode(mode);
+ if (result != Result::OK) {
+ ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
+ break;
+ }
+ }
+ if (result != Result::OK) {
+ // Reset the subhal operation modes that have been flipped
+ for (size_t i = 0; i < subHalIndex; i++) {
+ ISensorsSubHal* subHal = mSubHalList[i];
+ subHal->setOperationMode(mCurrentOperationMode);
+ }
+ } else {
+ mCurrentOperationMode = mode;
+ }
+ return result;
+}
+
+Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
+ if (!isSubHalIndexValid(sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
+ return getSubHalForSensorHandle(sensorHandle)
+ ->activate(clearSubHalIndex(sensorHandle), enabled);
+}
+
+Return<Result> HalProxy::initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+ const sp<ISensorsCallback>& sensorsCallback) {
+ Result result = Result::OK;
+
+ stopThreads();
+ resetSharedWakelock();
+
+ // So that the pending write events queue can be cleared safely and when we start threads
+ // again we do not get new events until after initialize resets the subhals.
+ disableAllSensors();
+
+ // Clears the queue if any events were pending write before.
+ mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();
+
+ // Clears previously connected dynamic sensors
+ mDynamicSensors.clear();
+
+ mDynamicSensorsCallback = sensorsCallback;
+
+ // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+ mEventQueue =
+ std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
+
+ // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+ // events have been successfully read and handled by the framework.
+ mWakeLockQueue =
+ std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+
+ if (mEventQueueFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+ }
+ if (mWakelockQueueFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mWakelockQueueFlag);
+ }
+ if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+ result = Result::BAD_VALUE;
+ }
+ if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
+ result = Result::BAD_VALUE;
+ }
+ if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+ result = Result::BAD_VALUE;
+ }
+
+ mThreadsRun.store(true);
+
+ mPendingWritesThread = std::thread(startPendingWritesThread, this);
+ mWakelockThread = std::thread(startWakelockThread, this);
+
+ for (size_t i = 0; i < mSubHalList.size(); i++) {
+ auto subHal = mSubHalList[i];
+ const auto& subHalCallback = mSubHalCallbacks[i];
+ Result currRes = subHal->initialize(subHalCallback);
+ if (currRes != Result::OK) {
+ result = currRes;
+ ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str());
+ break;
+ }
+ }
+
+ mCurrentOperationMode = OperationMode::NORMAL;
+
+ return result;
+}
+
+Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) {
+ if (!isSubHalIndexValid(sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
+ return getSubHalForSensorHandle(sensorHandle)
+ ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
+}
+
+Return<Result> HalProxy::flush(int32_t sensorHandle) {
+ if (!isSubHalIndexValid(sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
+ return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
+}
+
+Return<Result> HalProxy::injectSensorData(const Event& event) {
+ Result result = Result::OK;
+ if (mCurrentOperationMode == OperationMode::NORMAL &&
+ event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
+ ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
+ " mode was NORMAL.");
+ result = Result::BAD_VALUE;
+ }
+ if (result == Result::OK) {
+ Event subHalEvent = event;
+ if (!isSubHalIndexValid(event.sensorHandle)) {
+ return Result::BAD_VALUE;
+ }
+ subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
+ result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
+ }
+ return result;
+}
+
+Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
+ registerDirectChannel_cb _hidl_cb) {
+ if (mDirectChannelSubHal == nullptr) {
+ _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+ } else {
+ mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
+ }
+ return Return<void>();
+}
+
+Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
+ Result result;
+ if (mDirectChannelSubHal == nullptr) {
+ result = Result::INVALID_OPERATION;
+ } else {
+ result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
+ }
+ return result;
+}
+
+Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+ RateLevel rate, configDirectReport_cb _hidl_cb) {
+ if (mDirectChannelSubHal == nullptr) {
+ _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
+ } else {
+ mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle,
+ rate, _hidl_cb);
+ }
+ return Return<void>();
+}
+
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+ if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+ ALOGE("%s: missing fd for writing", __FUNCTION__);
+ return Void();
+ }
+
+ android::base::borrowed_fd writeFd = dup(fd->data[0]);
+
+ std::ostringstream stream;
+ stream << "===HalProxy===" << std::endl;
+ stream << "Internal values:" << std::endl;
+ stream << " Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
+ int64_t now = getTimeNow();
+ stream << " Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
+ << " ms ago" << std::endl;
+ stream << " Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
+ << " ms ago" << std::endl;
+ // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
+ stream << " Wakelock ref count: " << mWakelockRefCount << std::endl;
+ stream << " Size of pending write events queue: " << mPendingWriteEventsQueue.size()
+ << std::endl;
+ if (!mPendingWriteEventsQueue.empty()) {
+ stream << " Size of events list on front of pending writes queue: "
+ << mPendingWriteEventsQueue.front().first.size() << std::endl;
+ }
+ stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
+ stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
+ stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
+ for (ISensorsSubHal* subHal : mSubHalList) {
+ stream << " Name: " << subHal->getName() << std::endl;
+ stream << " Debug dump: " << std::endl;
+ android::base::WriteStringToFd(stream.str(), writeFd);
+ subHal->debug(fd, {});
+ stream.str("");
+ stream << std::endl;
+ }
+ android::base::WriteStringToFd(stream.str(), writeFd);
+ return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ int32_t subHalIndex) {
+ std::vector<SensorInfo> sensors;
+ {
+ std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+ for (SensorInfo sensor : dynamicSensorsAdded) {
+ if (!subHalIndexIsClear(sensor.sensorHandle)) {
+ ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
+ sensor.name.c_str());
+ } else {
+ sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+ mDynamicSensors[sensor.sensorHandle] = sensor;
+ sensors.push_back(sensor);
+ }
+ }
+ }
+ mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
+ return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
+ // TODO(b/143302327): Block this call until all pending events are flushed from queue
+ std::vector<int32_t> sensorHandles;
+ {
+ std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+ for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
+ if (!subHalIndexIsClear(sensorHandle)) {
+ ALOGE("Dynamic sensorHandle removed had first byte not 0.");
+ } else {
+ sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
+ if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
+ mDynamicSensors.erase(sensorHandle);
+ sensorHandles.push_back(sensorHandle);
+ }
+ }
+ }
+ }
+ mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
+ return Return<void>();
+}
+
+void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
+ std::ifstream subHalConfigStream(configFileName);
+ if (!subHalConfigStream) {
+ ALOGE("Failed to load subHal config file: %s", configFileName);
+ } else {
+ std::string subHalLibraryFile;
+ while (subHalConfigStream >> subHalLibraryFile) {
+ void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
+ if (handle == nullptr) {
+ ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
+ } else {
+ SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
+ (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
+ if (sensorsHalGetSubHalPtr == nullptr) {
+ ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
+ subHalLibraryFile.c_str());
+ } else {
+ std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
+ *sensorsHalGetSubHalPtr;
+ uint32_t version;
+ ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
+ if (version != SUB_HAL_2_0_VERSION) {
+ ALOGE("SubHal version was not 2.0 for library: %s",
+ subHalLibraryFile.c_str());
+ } else {
+ ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+ mSubHalList.push_back(subHal);
+ }
+ }
+ }
+ }
+ }
+}
+
+void HalProxy::initializeSubHalCallbacks() {
+ for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+ sp<IHalProxyCallback> callback = new HalProxyCallback(this, subHalIndex);
+ mSubHalCallbacks.push_back(callback);
+ }
+}
+
+void HalProxy::initializeSensorList() {
+ for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+ ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+ auto result = subHal->getSensorsList([&](const auto& list) {
+ for (SensorInfo sensor : list) {
+ if (!subHalIndexIsClear(sensor.sensorHandle)) {
+ ALOGE("SubHal sensorHandle's first byte was not 0");
+ } else {
+ ALOGV("Loaded sensor: %s", sensor.name.c_str());
+ sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+ setDirectChannelFlags(&sensor, subHal);
+ mSensors[sensor.sensorHandle] = sensor;
+ }
+ }
+ });
+ if (!result.isOk()) {
+ ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
+ }
+ }
+}
+
+void HalProxy::init() {
+ initializeSubHalCallbacks();
+ initializeSensorList();
+}
+
+void HalProxy::stopThreads() {
+ mThreadsRun.store(false);
+ if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
+ size_t numToRead = mEventQueue->availableToRead();
+ std::vector<Event> events(numToRead);
+ mEventQueue->read(events.data(), numToRead);
+ mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
+ }
+ if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
+ uint32_t kZero = 0;
+ mWakeLockQueue->write(&kZero);
+ mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+ }
+ mWakelockCV.notify_one();
+ mEventQueueWriteCV.notify_one();
+ if (mPendingWritesThread.joinable()) {
+ mPendingWritesThread.join();
+ }
+ if (mWakelockThread.joinable()) {
+ mWakelockThread.join();
+ }
+}
+
+void HalProxy::disableAllSensors() {
+ for (const auto& sensorEntry : mSensors) {
+ int32_t sensorHandle = sensorEntry.first;
+ activate(sensorHandle, false /* enabled */);
+ }
+ std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
+ for (const auto& sensorEntry : mDynamicSensors) {
+ int32_t sensorHandle = sensorEntry.first;
+ activate(sensorHandle, false /* enabled */);
+ }
+}
+
+void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
+ halProxy->handlePendingWrites();
+}
+
+void HalProxy::handlePendingWrites() {
+ // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
+ // one.
+ std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
+ while (mThreadsRun.load()) {
+ mEventQueueWriteCV.wait(
+ lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
+ if (mThreadsRun.load()) {
+ std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
+ size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
+ size_t eventQueueSize = mEventQueue->getQuantumCount();
+ size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
+ lock.unlock();
+ if (!mEventQueue->writeBlocking(
+ pendingWriteEvents.data(), numToWrite,
+ static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+ static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+ kPendingWriteTimeoutNs, mEventQueueFlag)) {
+ ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
+ if (numWakeupEvents > 0) {
+ if (pendingWriteEvents.size() > eventQueueSize) {
+ decrementRefCountAndMaybeReleaseWakelock(
+ countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
+ } else {
+ decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
+ }
+ }
+ }
+ lock.lock();
+ if (pendingWriteEvents.size() > eventQueueSize) {
+ // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
+ // all the events ahead of it down to fill gap off array at front after the erase.
+ pendingWriteEvents.erase(pendingWriteEvents.begin(),
+ pendingWriteEvents.begin() + eventQueueSize);
+ } else {
+ mPendingWriteEventsQueue.pop();
+ }
+ }
+ }
+}
+
+void HalProxy::startWakelockThread(HalProxy* halProxy) {
+ halProxy->handleWakelocks();
+}
+
+void HalProxy::handleWakelocks() {
+ std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
+ while (mThreadsRun.load()) {
+ mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
+ if (mThreadsRun.load()) {
+ int64_t timeLeft;
+ if (sharedWakelockDidTimeout(&timeLeft)) {
+ resetSharedWakelock();
+ } else {
+ uint32_t numWakeLocksProcessed;
+ lock.unlock();
+ bool success = mWakeLockQueue->readBlocking(
+ &numWakeLocksProcessed, 1, 0,
+ static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
+ lock.lock();
+ if (success) {
+ decrementRefCountAndMaybeReleaseWakelock(
+ static_cast<size_t>(numWakeLocksProcessed));
+ }
+ }
+ }
+ }
+ resetSharedWakelock();
+}
+
+bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
+ bool didTimeout;
+ int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
+ if (duration > kWakelockTimeoutNs) {
+ didTimeout = true;
+ } else {
+ didTimeout = false;
+ *timeLeft = kWakelockTimeoutNs - duration;
+ }
+ return didTimeout;
+}
+
+void HalProxy::resetSharedWakelock() {
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
+ mWakelockTimeoutResetTime = getTimeNow();
+}
+
+void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+ ScopedWakelock wakelock) {
+ size_t numToWrite = 0;
+ std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+ if (wakelock.isLocked()) {
+ incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
+ }
+ if (mPendingWriteEventsQueue.empty()) {
+ numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
+ if (numToWrite > 0) {
+ if (mEventQueue->write(events.data(), numToWrite)) {
+ // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
+ // in more writes immediately
+ mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+ } else {
+ numToWrite = 0;
+ }
+ }
+ }
+ if (numToWrite < events.size()) {
+ // TODO(b/143302327): Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if
+ // framework stalls
+ std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
+ mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
+ mEventQueueWriteCV.notify_one();
+ }
+}
+
+bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart /* = nullptr */) {
+ if (!mThreadsRun.load()) return false;
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ if (mWakelockRefCount == 0) {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
+ mWakelockCV.notify_one();
+ }
+ mWakelockTimeoutStartTime = getTimeNow();
+ mWakelockRefCount += delta;
+ if (timeoutStart != nullptr) {
+ *timeoutStart = mWakelockTimeoutStartTime;
+ }
+ return true;
+}
+
+void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+ int64_t timeoutStart /* = -1 */) {
+ if (!mThreadsRun.load()) return;
+ std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+ if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
+ if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
+ mWakelockRefCount -= std::min(mWakelockRefCount, delta);
+ if (mWakelockRefCount == 0) {
+ release_wake_lock(kWakelockName);
+ }
+}
+
+void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
+ bool sensorSupportsDirectChannel =
+ (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+ V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
+ if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
+ mDirectChannelSubHal = subHal;
+ } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
+ // disable direct channel capability for sensors in subHals that are not
+ // the only one we will enable
+ sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+ V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+ }
+}
+
+ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
+ return mSubHalList[extractSubHalIndex(sensorHandle)];
+}
+
+bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
+ return extractSubHalIndex(sensorHandle) < mSubHalList.size();
+}
+
+size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
+ size_t numWakeupEvents = 0;
+ for (size_t i = 0; i < n; i++) {
+ int32_t sensorHandle = events[i].sensorHandle;
+ if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
+ numWakeupEvents++;
+ }
+ }
+ return numWakeupEvents;
+}
+
+int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
+ return sensorHandle & (~kSensorHandleSubHalIndexMask);
+}
+
+bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
+ return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
+}
+
+void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
+ if (events.empty() || !mHalProxy->areThreadsRunning()) return;
+ size_t numWakeupEvents;
+ std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
+ if (numWakeupEvents > 0) {
+ ALOG_ASSERT(wakelock.isLocked(),
+ "Wakeup events posted while wakelock unlocked for subhal"
+ " w/ index %zu.",
+ mSubHalIndex);
+ } else {
+ ALOG_ASSERT(!wakelock.isLocked(),
+ "No Wakeup events posted but wakelock locked for subhal"
+ " w/ index %zu.",
+ mSubHalIndex);
+ }
+ mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
+}
+
+ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
+ ScopedWakelock wakelock(mHalProxy, lock);
+ return wakelock;
+}
+
+std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
+ size_t* numWakeupEvents) const {
+ *numWakeupEvents = 0;
+ std::vector<Event> eventsOut;
+ for (Event event : events) {
+ event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
+ eventsOut.push_back(event);
+ const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
+ if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
+ (*numWakeupEvents)++;
+ }
+ }
+ return eventsOut;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
new file mode 100644
index 0000000..e955670
--- /dev/null
+++ b/sensors/2.0/multihal/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp
new file mode 100644
index 0000000..d85d4a7
--- /dev/null
+++ b/sensors/2.0/multihal/ScopedWakelock.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ScopedWakelock.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+int64_t getTimeNow() {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now().time_since_epoch())
+ .count();
+}
+
+ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
+ : mRefCounter(refCounter), mLocked(locked) {
+ if (mLocked) {
+ mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
+ }
+}
+
+ScopedWakelock::~ScopedWakelock() {
+ if (mLocked) {
+ mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
new file mode 100644
index 0000000..a771100
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.sensors</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>ISensors</name>
+ <instance>multihal</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
new file mode 100644
index 0000000..a4da3b0
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
+ class hal
+ user system
+ group system wakelock
+ writepid /dev/cpuset/system-background/tasks
+ capabilities BLOCK_SUSPEND
+ rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
new file mode 100644
index 0000000..b1dd737
--- /dev/null
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "ScopedWakelock.h"
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+class HalProxy : public ISensors, public IScopedWakelockRefCounter {
+ public:
+ using Event = ::android::hardware::sensors::V1_0::Event;
+ using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
+ using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+ using Result = ::android::hardware::sensors::V1_0::Result;
+ using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
+ using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+ using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+ explicit HalProxy();
+ // Test only constructor.
+ explicit HalProxy(std::vector<ISensorsSubHal*>& subHalList);
+ ~HalProxy();
+
+ // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+ Return<Result> setOperationMode(OperationMode mode) override;
+
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+ const sp<ISensorsCallback>& sensorsCallback) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ Return<Result> flush(int32_t sensorHandle) override;
+
+ Return<Result> injectSensorData(const Event& event) override;
+
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) override;
+
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+ // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change
+ // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
+ // via the binder, these methods are invoked from a callback provided to sub-HALs inside the
+ // same process as the HalProxy, but potentially running on different threads.
+ Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ int32_t subHalIndex);
+
+ Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
+ int32_t subHalIndex);
+
+ // Below methods are for HalProxyCallback
+
+ /**
+ * Post events to the event message queue if there is room to write them. Otherwise post the
+ * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
+ * timeout.
+ *
+ * @param events The list of events to post to the message queue.
+ * @param numWakeupEvents The number of wakeup events in events.
+ * @param wakelock The wakelock associated with this post of events.
+ */
+ void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+ ScopedWakelock wakelock);
+
+ /**
+ * Get the sensor info associated with that sensorHandle.
+ *
+ * @param sensorHandle The sensor handle.
+ *
+ * @return The sensor info object in the mapping.
+ */
+ const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; }
+
+ bool areThreadsRunning() { return mThreadsRun.load(); }
+
+ // Below methods are from IScopedWakelockRefCounter interface
+ bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart = nullptr) override;
+
+ void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
+
+ private:
+ using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
+ using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+ /**
+ * The Event FMQ where sensor events are written
+ */
+ std::unique_ptr<EventMessageQueue> mEventQueue;
+
+ /**
+ * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+ */
+ std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+
+ /**
+ * Event Flag to signal to the framework when sensor events are available to be read and to
+ * interrupt event queue blocking write.
+ */
+ EventFlag* mEventQueueFlag = nullptr;
+
+ //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
+ EventFlag* mWakelockQueueFlag = nullptr;
+
+ /**
+ * Callback to the sensors framework to inform it that new sensors have been added or removed.
+ */
+ sp<ISensorsCallback> mDynamicSensorsCallback;
+
+ /**
+ * SubHal object pointers that have been saved from vendor dynamic libraries.
+ */
+ std::vector<ISensorsSubHal*> mSubHalList;
+
+ //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList
+ std::vector<const sp<IHalProxyCallback>> mSubHalCallbacks;
+
+ /**
+ * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as
+ * well as the modified sensor handle for the framework.
+ *
+ * The subhal index is encoded in the first byte of the sensor handle and the remaining
+ * bytes are generated by the subhal to identify the sensor.
+ */
+ std::map<int32_t, SensorInfo> mSensors;
+
+ //! Map of the dynamic sensors that have been added to halproxy.
+ std::map<int32_t, SensorInfo> mDynamicSensors;
+
+ //! The current operation mode for all subhals.
+ OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+ //! The single subHal that supports directChannel reporting.
+ ISensorsSubHal* mDirectChannelSubHal = nullptr;
+
+ //! The timeout for each pending write on background thread for events.
+ static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
+
+ //! The bit mask used to get the subhal index from a sensor handle.
+ static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
+
+ /**
+ * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
+ * which are waiting to be written to the events fmq in the background thread.
+ */
+ std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
+
+ //! The mutex protecting writing to the fmq and the pending events queue
+ std::mutex mEventQueueWriteMutex;
+
+ //! The condition variable waiting on pending write events to stack up
+ std::condition_variable mEventQueueWriteCV;
+
+ //! The thread object ptr that handles pending writes
+ std::thread mPendingWritesThread;
+
+ //! The thread object that handles wakelocks
+ std::thread mWakelockThread;
+
+ //! The bool indicating whether to end the threads started in initialize
+ std::atomic_bool mThreadsRun = true;
+
+ //! The mutex protecting access to the dynamic sensors added and removed methods.
+ std::mutex mDynamicSensorsMutex;
+
+ // WakelockRefCount membar vars below
+
+ //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
+ //! acquisitions
+ std::recursive_mutex mWakelockMutex;
+
+ std::condition_variable_any mWakelockCV;
+
+ //! The refcount of how many ScopedWakelocks and pending wakeup events are active
+ size_t mWakelockRefCount = 0;
+
+ int64_t mWakelockTimeoutStartTime = getTimeNow();
+
+ int64_t mWakelockTimeoutResetTime = getTimeNow();
+
+ const char* kWakelockName = "SensorsHAL_WAKEUP";
+
+ /**
+ * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
+ * listed in a config file.
+ */
+ void initializeSubHalListFromConfigFile(const char* configFileName);
+
+ /**
+ * Initialize the HalProxyCallback vector using the list of subhals.
+ */
+ void initializeSubHalCallbacks();
+
+ /**
+ * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
+ * subhal.
+ */
+ void initializeSensorList();
+
+ /**
+ * Calls the helper methods that all ctors use.
+ */
+ void init();
+
+ /**
+ * Stops all threads by setting the threads running flag to false and joining to them.
+ */
+ void stopThreads();
+
+ /**
+ * Disable all the sensors observed by the HalProxy.
+ */
+ void disableAllSensors();
+
+ /**
+ * Starts the thread that handles pending writes to event fmq.
+ *
+ * @param halProxy The HalProxy object pointer.
+ */
+ static void startPendingWritesThread(HalProxy* halProxy);
+
+ //! Handles the pending writes on events to eventqueue.
+ void handlePendingWrites();
+
+ /**
+ * Starts the thread that handles decrementing the ref count on wakeup events processed by the
+ * framework and timing out wakelocks.
+ *
+ * @param halProxy The HalProxy object pointer.
+ */
+ static void startWakelockThread(HalProxy* halProxy);
+
+ //! Handles the wakelocks.
+ void handleWakelocks();
+
+ /**
+ * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
+ * unmodified if timeout occurred.
+ *
+ * @return true if the shared wakelock has been held passed the timeout and should be released
+ */
+ bool sharedWakelockDidTimeout(int64_t* timeLeft);
+
+ /**
+ * Reset all the member variables associated with the wakelock ref count and maybe release
+ * the shared wakelock.
+ */
+ void resetSharedWakelock();
+
+ /**
+ * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
+ * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
+ * direct channel enabled sensor seen.
+ *
+ * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
+ * disabled.
+ * @param subHal The subhal pointer that the current sensorInfo object came from.
+ */
+ void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);
+
+ /*
+ * Get the subhal pointer which can be found by indexing into the mSubHalList vector
+ * using the index from the first byte of sensorHandle.
+ *
+ * @param sensorHandle The handle used to identify a sensor in one of the subhals.
+ */
+ ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle);
+
+ /**
+ * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
+ *
+ * @param sensorHandle The sensor handle to check.
+ *
+ * @return true if sensorHandles's subhal index byte is valid.
+ */
+ bool isSubHalIndexValid(int32_t sensorHandle);
+
+ /**
+ * Count the number of wakeup events in the first n events of the vector.
+ *
+ * @param events The vector of Event objects.
+ * @param n The end index not inclusive of events to consider.
+ *
+ * @return The number of wakeup events of the considered events.
+ */
+ size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
+
+ /*
+ * Clear out the subhal index bytes from a sensorHandle.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ *
+ * @return The modified version of the sensor handle.
+ */
+ static int32_t clearSubHalIndex(int32_t sensorHandle);
+
+ /**
+ * @param sensorHandle The sensor handle to modify.
+ *
+ * @return true if subHalIndex byte of sensorHandle is zeroed.
+ */
+ static bool subHalIndexIsClear(int32_t sensorHandle);
+};
+
+/**
+ * Callback class used to provide the HalProxy with the index of which subHal is invoking
+ */
+class HalProxyCallback : public IHalProxyCallback {
+ using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
+
+ public:
+ HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex)
+ : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {}
+
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+ return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+ return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
+ }
+
+ void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock);
+
+ ScopedWakelock createScopedWakelock(bool lock);
+
+ private:
+ HalProxy* mHalProxy;
+ int32_t mSubHalIndex;
+
+ std::vector<Event> processEvents(const std::vector<Event>& events,
+ size_t* numWakeupEvents) const;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h
new file mode 100644
index 0000000..aa6d9db
--- /dev/null
+++ b/sensors/2.0/multihal/include/ScopedWakelock.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+const int64_t kWakelockTimeoutNs =
+ static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
+
+int64_t getTimeNow();
+
+class IScopedWakelockRefCounter : public RefBase {
+ public:
+ /**
+ * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
+ * from 0 then return the time of incrementing back to caller.
+ *
+ * @param delta The amount to change ref count by.
+ * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
+ * set in the function or nullptr if not specified.
+ *
+ * @return true if successfully incremented the wakelock ref count.
+ */
+ virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+ int64_t* timeoutStart = nullptr) = 0;
+ /**
+ * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
+ *
+ * @param delta The amount to change ref count by.
+ * @param timeoutStart The timestamp in ns that the calling context kept track of when
+ * incrementing the ref count or -1 by default
+ */
+ virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+ int64_t timeoutStart = -1) = 0;
+ // Virtual dtor needed for compilation success
+ virtual ~IScopedWakelockRefCounter(){};
+};
+
+/**
+ * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
+ * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
+ * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
+ * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
+ * out of scope, the ref count is decremented, potentially releasing the wake lock if no other
+ * references to the wake lock exist.
+ *
+ * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
+ * provided to sub-HALs during initialization and should be used for all wake lock acquisition
+ * inside of the sub-HAL to ensure wake locks are not held indefinitely.
+ *
+ * The most prevalent use case for this class will be for posting events to the framework through
+ * the postEvents HalProxy callback. The expectation is that sub-HALs will create this
+ * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
+ * provided to createScopedWakelock will be set the according to whether the sensor events are
+ * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
+ * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
+ * of the object will be passed to the HalProxy that will then be responsible for ensuring any
+ * wake locks continue to be held, if necessary.
+ */
+class ScopedWakelock {
+ public:
+ ScopedWakelock(ScopedWakelock&&) = default;
+ ScopedWakelock& operator=(ScopedWakelock&&) = default;
+ virtual ~ScopedWakelock();
+
+ bool isLocked() const { return mLocked; }
+
+ private:
+ friend class HalProxyCallback;
+ IScopedWakelockRefCounter* mRefCounter;
+ int64_t mCreatedAtTimeNs;
+ bool mLocked;
+ ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
+ ScopedWakelock(const ScopedWakelock&) = delete;
+ ScopedWakelock& operator=(const ScopedWakelock&) = delete;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
new file mode 100644
index 0000000..92ae3a6
--- /dev/null
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "ScopedWakelock.h"
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+#include <vector>
+
+// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
+// (HAL minor version) << 16 | (multiHAL version)
+#define SUB_HAL_2_0_VERSION 0x02000000
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+
+/**
+ * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
+ * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
+ * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
+ * manner.
+ */
+class IHalProxyCallback : public ISensorsCallback {
+ public:
+ /**
+ * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
+ * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
+ * HalProxy will attempt to send events to the sensors framework using a blocking write with a
+ * 5 second timeout. This write may be done asynchronously if the queue used to communicate
+ * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
+ * write fails, the events will be dropped and any wake locks held will be released.
+ *
+ * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
+ * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
+ * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
+ * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
+ * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
+ * framework has successfully processed any wakeup events.
+ *
+ * No return type is used for this callback to avoid sub-HALs trying to resend events when
+ * writes fail. Writes should only fail when the framework is under inordinate stress which will
+ * likely result in a framework restart so retrying will likely only result in overloading the
+ * HalProxy. Sub-HALs should always assume that the write was a success and perform any
+ * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
+ * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
+ *
+ * @param events the events that should be sent to the sensors framework
+ * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
+ * unlocked otherwise.
+ */
+ virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
+
+ /**
+ * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
+ * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
+ * definition for how it should be used.
+ *
+ * @param lock whether the ScopedWakelock should be locked before it's returned.
+ * @return the created ScopedWakelock
+ */
+ virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+/**
+ * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
+ * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
+ *
+ * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
+ * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
+ * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
+ * implementation of sensorsHalGetSubHal.
+ *
+ * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
+ * Any sensor handles given to the HalProxy, either through getSensorsList() or the
+ * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
+ * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
+ * sub-HALs can continue to use the lower 3 bytes of the handle.
+ */
+class ISensorsSubHal : public ISensors {
+ public:
+ // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
+ // the version below to allow communciation logic to centralized in the HalProxy
+ Return<Result> initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+ const sp<ISensorsCallback>& /* sensorsCallback */) final {
+ return Result::INVALID_OPERATION;
+ }
+
+ /**
+ * Method defined in ::android::hidl::base::V1_0::IBase.
+ *
+ * This method should write debug information to hidl_handle that is useful for debugging
+ * issues. Suggestions include:
+ * - Sensor info including handle values and any other state available in the SensorInfo class
+ * - List of active sensors and their current sampling period and reporting latency
+ * - Information about pending flush requests
+ * - Current operating mode
+ * - Currently registered direct channel info
+ * - A history of any of the above
+ */
+ virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+ /**
+ * @return A human-readable name for use in wake locks and logging.
+ */
+ virtual const std::string getName() = 0;
+
+ /**
+ * This is the first method invoked on the sub-HAL after it's allocated through
+ * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
+ * retain the callback given in order to communicate with the HalProxy. Method will be called
+ * anytime the sensors framework restarts. Therefore, this method will be responsible for
+ * reseting the state of the subhal and cleaning up and reallocating any previously allocated
+ * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
+ * as well.
+ *
+ * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
+ * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+ * should be created.
+ * @return result OK on success
+ */
+ virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+/**
+ * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
+ * library. This function will only be invoked once at initialization time.
+ *
+ * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
+ * will fail to initialize.
+ *
+ * @param uint32_t when this function returns, this parameter must contain the HAL version that
+ * this sub-HAL supports. To support this version of multi-HAL, this must be set to
+ * SUB_HAL_2_0_VERSION.
+ * @return A statically allocated, valid ISensorsSubHal implementation.
+ */
+__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
+ uint32_t* version);
diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp
new file mode 100644
index 0000000..ef77048
--- /dev/null
+++ b/sensors/2.0/multihal/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "HalProxy.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_0::ISensors;
+using android::hardware::sensors::V2_0::implementation::HalProxy;
+
+int main(int /* argc */, char** /* argv */) {
+ configureRpcThreadpool(1, true);
+
+ android::sp<ISensors> halProxy = new HalProxy();
+ if (halProxy->registerAsService() != ::android::OK) {
+ ALOGE("Failed to register Sensors HAL instance");
+ return -1;
+ }
+
+ joinRpcThreadpool();
+ return 1; // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
new file mode 100644
index 0000000..e7f9499
--- /dev/null
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -0,0 +1,99 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "android.hardware.sensors@2.0-fakesubhal-defaults",
+ srcs: [
+ "fake_subhal/*.cpp",
+ ],
+ header_libs: [
+ "android.hardware.sensors@2.0-multihal.header",
+ ],
+ export_include_dirs: ["fake_subhal"],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libpower",
+ "libutils",
+ ],
+ static_libs: [
+ "android.hardware.sensors@2.0-HalProxy",
+ ],
+ cflags: [
+ "-DLOG_TAG=\"FakeSubHal\""
+ ],
+}
+
+cc_library {
+ name: "android.hardware.sensors@2.0-fakesubhal-config1",
+ vendor: true,
+ defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+ cflags: [
+ "-DSUPPORT_CONTINUOUS_SENSORS",
+ "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
+ ],
+}
+
+cc_library {
+ name: "android.hardware.sensors@2.0-fakesubhal-config2",
+ vendor: true,
+ defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+ cflags: [
+ "-DSUPPORT_ON_CHANGE_SENSORS",
+ "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
+ ],
+}
+
+cc_test_library {
+ name: "android.hardware.sensors@2.0-fakesubhal-unittest",
+ vendor_available: true,
+ defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+ cflags: [
+ "-DSUPPORT_ON_CHANGE_SENSORS",
+ "-DSUPPORT_CONTINUOUS_SENSORS",
+ "-DSUB_HAL_NAME=\"FakeSubHal-Test\"",
+ ],
+}
+
+cc_test {
+ name: "android.hardware.sensors@2.0-halproxy-unit-tests",
+ srcs: ["HalProxy_test.cpp"],
+ vendor: true,
+ static_libs: [
+ "android.hardware.sensors@2.0-HalProxy",
+ "android.hardware.sensors@2.0-fakesubhal-unittest",
+ ],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libpower",
+ "libutils",
+ ],
+ test_suites: ["device-tests"],
+ cflags: [
+ "-DLOG_TAG=\"HalProxyUnitTests\"",
+ ],
+}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
new file mode 100644
index 0000000..1fd35d1
--- /dev/null
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -0,0 +1,833 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gtest/gtest.h>
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+
+#include "HalProxy.h"
+#include "ScopedWakelock.h"
+#include "SensorsSubHal.h"
+
+#include <chrono>
+#include <set>
+#include <thread>
+#include <vector>
+
+namespace {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::EventPayload;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::ISensorsCallback;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::HalProxy;
+using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+ AllSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+ DoesNotSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+ SetOperationModeFailingSensorsSubHal;
+
+using EventMessageQueue = MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite>;
+using WakeupMessageQueue = MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite>;
+
+// The barebones sensors callback class passed into halproxy initialize calls
+class SensorsCallback : public ISensorsCallback {
+ public:
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
+ // Nothing yet
+ return Return<void>();
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
+ // Nothing yet
+ return Return<void>();
+ }
+};
+
+// The sensors callback that expects a variable list of sensors to be added
+class TestSensorsCallback : public ISensorsCallback {
+ public:
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+ mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
+ dynamicSensorsAdded.end());
+ return Return<void>();
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+ mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
+ dynamicSensorHandlesRemoved.begin(),
+ dynamicSensorHandlesRemoved.end());
+ return Return<void>();
+ }
+
+ const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
+ const std::vector<int32_t>& getSensorHandlesDisconnected() const {
+ return mSensorHandlesDisconnected;
+ }
+
+ private:
+ std::vector<SensorInfo> mSensorsConnected;
+ std::vector<int32_t> mSensorHandlesDisconnected;
+};
+
+// Helper declarations follow
+
+/**
+ * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
+ * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
+ * same for sensorHandle field.
+ *
+ * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
+ * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
+ */
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+ const std::vector<SensorInfo>& subHalSensorsList);
+
+/**
+ * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
+ * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
+ * direct channel.
+ *
+ * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
+ * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
+ * enabled.
+ */
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+ size_t enabledSubHalIndex);
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+ EventFlag* wakelockQueueFlag);
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+ EventFlag* eventQueueFlag);
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ * which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+Event makeProximityEvent();
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ * which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+Event makeAccelerometerEvent();
+
+/**
+ * Make a certain number of proximity type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents);
+
+/**
+ * Make a certain number of accelerometer type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
+
+/**
+ * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
+ * objects that have the sensorHandle property set to int32_ts from start to start + size
+ * (exclusive) and push those sensorHandles also onto 'sensorHandles'.
+ *
+ * @param start The starting sensorHandle value.
+ * @param size The ending (not included) sensorHandle value.
+ * @param sensors The SensorInfo object vector reference to push_back to.
+ * @param sensorHandles The sensor handles int32_t vector reference to push_back to.
+ */
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+ std::vector<SensorInfo>& sensors,
+ std::vector<int32_t>& sensorHandles);
+
+// Tests follow
+TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
+ HalProxy proxy(fakeSubHals);
+
+ proxy.getSensorsList([&](const auto& proxySensorsList) {
+ subHal.getSensorsList([&](const auto& subHalSensorsList) {
+ testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
+ });
+ });
+}
+
+TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
+ ContinuousSensorsSubHal continuousSubHal;
+ OnChangeSensorsSubHal onChangeSubHal;
+ std::vector<ISensorsSubHal*> fakeSubHals;
+ fakeSubHals.push_back(&continuousSubHal);
+ fakeSubHals.push_back(&onChangeSubHal);
+ HalProxy proxy(fakeSubHals);
+
+ std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
+
+ proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
+ continuousSubHal.getSensorsList([&](const auto& list) {
+ combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+ });
+ onChangeSubHal.getSensorsList([&](const auto& list) {
+ combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+ });
+
+ testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
+ ContinuousSensorsSubHal subHal1;
+ OnChangeSensorsSubHal subHal2;
+
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+ HalProxy proxy(fakeSubHals);
+
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+ Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+ EXPECT_EQ(result, Result::OK);
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
+ AllSensorsSubHal subHal1;
+ SetOperationModeFailingSensorsSubHal subHal2;
+
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+ HalProxy proxy(fakeSubHals);
+
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+ Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+ EXPECT_NE(result, Result::OK);
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+}
+
+TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
+ AllSupportDirectChannelSensorsSubHal subHal1;
+ AllSupportDirectChannelSensorsSubHal subHal2;
+
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+ HalProxy proxy(fakeSubHals);
+
+ proxy.getSensorsList([&](const auto& sensorsList) {
+ testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
+ });
+}
+
+TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
+ DoesNotSupportDirectChannelSensorsSubHal subHal1;
+ AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
+ HalProxy proxy(fakeSubHals);
+
+ proxy.getSensorsList([&](const auto& sensorsList) {
+ testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
+ });
+}
+
+TEST(HalProxyTest, PostSingleNonWakeupEvent) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events{makeAccelerometerEvent()};
+ subHal.postEvents(events, false /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), 1);
+}
+
+TEST(HalProxyTest, PostMultipleNonWakeupEvent) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 3;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+ subHal.postEvents(events, false /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+}
+
+TEST(HalProxyTest, PostSingleWakeupEvent) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ EventFlag* wakelockQueueFlag;
+ EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+ std::vector<Event> events{makeProximityEvent()};
+ subHal.postEvents(events, true /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), 1);
+
+ readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
+ ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostMultipleWakeupEvents) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 3;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ EventFlag* wakelockQueueFlag;
+ EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+ std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
+ subHal.postEvents(events, true /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+ readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
+ ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhals) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 2;
+ AllSensorsSubHal subHal1, subHal2;
+ std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+ subHal1.postEvents(events, false /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+ subHal2.postEvents(events, false /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, PostEventsDelayedWrite) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 6;
+ AllSensorsSubHal subHal1, subHal2;
+ std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ EventFlag* eventQueueFlag;
+ EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+ subHal1.postEvents(events, false /* wakeup */);
+
+ EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+
+ // readblock a full queue size worth of events out of queue, timeout for half a second
+ EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
+
+ // proxy background thread should have wrote remaining events when it saw space
+ EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
+
+ EXPECT_EQ(eventQueue->availableToRead(), 0);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 2;
+ AllSensorsSubHal subHal1, subHal2;
+ std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+
+ std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false);
+ std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false);
+
+ t1.join();
+ t2.join();
+
+ EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 6;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+ subHal.postEvents(events, false /* wakeup */);
+
+ // Destructing HalProxy object with events on the background thread
+}
+
+TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events{makeProximityEvent()};
+ subHal.postEvents(events, true /* wakeup */);
+
+ // Not sending any acks back through wakeLockQueue
+
+ // Destructing HalProxy object with unacked wakeup events posted
+}
+
+TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumEvents = 10;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+ subHal.postEvents(events, false /* wakeup */);
+
+ eventQueue = makeEventFMQ(kQueueSize);
+ wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+ Result secondInitResult =
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EXPECT_EQ(secondInitResult, Result::OK);
+ // Small sleep so that pending writes thread has a change to hit writeBlocking call.
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ Event eventOut;
+ EXPECT_FALSE(eventQueue->read(&eventOut));
+}
+
+TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ std::vector<Event> events{makeProximityEvent()};
+ subHal.postEvents(events, true /* wakeup */);
+
+ // Not sending any acks back through wakeLockQueue
+
+ eventQueue = makeEventFMQ(kQueueSize);
+ wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+ Result secondInitResult =
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EXPECT_EQ(secondInitResult, Result::OK);
+}
+
+TEST(HalProxyTest, InitializeManyTimesInARow) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumTimesToInit = 100;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+
+ for (size_t i = 0; i < kNumTimesToInit; i++) {
+ Result secondInitResult =
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ EXPECT_EQ(secondInitResult, Result::OK);
+ }
+}
+
+TEST(HalProxyTest, OperationModeResetOnInitialize) {
+ constexpr size_t kQueueSize = 5;
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.setOperationMode(OperationMode::DATA_INJECTION);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+ Event event = makeAccelerometerEvent();
+ // Should not be able to inject a non AdditionInfo type event because operation mode should
+ // have been reset to NORMAL
+ EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
+ constexpr size_t kQueueSize = 5;
+ constexpr size_t kNumSensors = 5;
+ AddAndRemoveDynamicSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ HalProxy proxy(subHals);
+
+ std::vector<SensorInfo> sensorsToConnect;
+ std::vector<int32_t> sensorHandlesToAttemptToRemove;
+ makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+ sensorHandlesToAttemptToRemove);
+
+ std::vector<int32_t> nonDynamicSensorHandles;
+ for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+ nonDynamicSensorHandles.push_back(sensorHandle);
+ }
+
+ TestSensorsCallback* callback = new TestSensorsCallback();
+ ::android::sp<ISensorsCallback> callbackPtr = callback;
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.addDynamicSensors(sensorsToConnect);
+
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+ std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
+
+ // Should not have received the sensorHandles for any dynamic sensors that were removed since
+ // all of them should have been removed in the second initialize call.
+ EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
+}
+
+TEST(HalProxyTest, DynamicSensorsConnectedTest) {
+ constexpr size_t kNumSensors = 3;
+ AddAndRemoveDynamicSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+ std::vector<SensorInfo> sensorsToConnect;
+ std::vector<int32_t> sensorHandlesToExpect;
+ makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+ sensorHandlesToExpect);
+
+ TestSensorsCallback* callback = new TestSensorsCallback();
+ ::android::sp<ISensorsCallback> callbackPtr = callback;
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.addDynamicSensors(sensorsToConnect);
+
+ std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
+ EXPECT_EQ(kNumSensors, sensorsSeen.size());
+ for (size_t i = 0; i < kNumSensors; i++) {
+ auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
+ // Note since only one subhal we do not need to change first byte for expected
+ auto sensorHandleExpected = sensorHandlesToExpect[i];
+ EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+ }
+}
+
+TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
+ constexpr size_t kNumSensors = 3;
+ AddAndRemoveDynamicSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> subHals{&subHal};
+ HalProxy proxy(subHals);
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+ std::vector<SensorInfo> sensorsToConnect;
+ std::vector<int32_t> sensorHandlesToExpect;
+ makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
+ sensorHandlesToExpect);
+
+ std::vector<int32_t> nonDynamicSensorHandles;
+ for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+ nonDynamicSensorHandles.push_back(sensorHandle);
+ }
+
+ std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
+ nonDynamicSensorHandles.end());
+
+ std::vector<int32_t> sensorHandlesToAttemptToRemove;
+ sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+ sensorHandlesToExpect.begin(),
+ sensorHandlesToExpect.end());
+ sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+ nonDynamicSensorHandles.begin(),
+ nonDynamicSensorHandles.end());
+
+ TestSensorsCallback* callback = new TestSensorsCallback();
+ ::android::sp<ISensorsCallback> callbackPtr = callback;
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+ subHal.addDynamicSensors(sensorsToConnect);
+ subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+ std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
+ EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
+ for (size_t i = 0; i < kNumSensors; i++) {
+ auto sensorHandleSeen = sensorHandlesSeen[i];
+ // Note since only one subhal we do not need to change first byte for expected
+ auto sensorHandleExpected = sensorHandlesToExpect[i];
+ EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+ EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
+ nonDynamicSensorHandlesSet.end());
+ }
+}
+
+TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
+ constexpr size_t kNumSubHals = 3;
+ constexpr size_t kQueueSize = 5;
+ int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
+ std::vector<AllSensorsSubHal> subHalObjs(kNumSubHals);
+ std::vector<ISensorsSubHal*> subHals;
+ for (const auto& subHal : subHalObjs) {
+ subHals.push_back((ISensorsSubHal*)(&subHal));
+ }
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ // Initialize for the injectSensorData call so callback postEvents is valid
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ // For testing proxy.injectSensorData properly
+ proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+ // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
+ EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
+ EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
+ EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
+ Event event;
+ event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
+ EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
+ constexpr size_t kQueueSize = 5;
+ constexpr int32_t subhal1Index = 0;
+ constexpr int32_t subhal2Index = 1;
+ AllSensorsSubHal subhal1;
+ AllSensorsSubHal subhal2;
+ std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
+
+ std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+ std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+ ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+ HalProxy proxy(subHals);
+ proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+ int32_t sensorHandleToPost = 0x00000001;
+ Event eventIn = makeAccelerometerEvent();
+ eventIn.sensorHandle = sensorHandleToPost;
+ std::vector<Event> eventsToPost{eventIn};
+ subhal1.postEvents(eventsToPost, false);
+
+ Event eventOut;
+ EXPECT_TRUE(eventQueue->read(&eventOut));
+
+ EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
+
+ subhal2.postEvents(eventsToPost, false);
+
+ EXPECT_TRUE(eventQueue->read(&eventOut));
+
+ EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
+}
+
+// Helper implementations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+ const std::vector<SensorInfo>& subHalSensorsList) {
+ EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
+
+ for (size_t i = 0; i < proxySensorsList.size(); i++) {
+ const SensorInfo& proxySensor = proxySensorsList[i];
+ const SensorInfo& subHalSensor = subHalSensorsList[i];
+
+ EXPECT_EQ(proxySensor.type, subHalSensor.type);
+ EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
+ }
+}
+
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+ size_t enabledSubHalIndex) {
+ for (const SensorInfo& sensor : sensorsList) {
+ size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
+ if (subHalIndex == enabledSubHalIndex) {
+ // First subhal should have been picked as the direct channel subhal
+ // and so have direct channel enabled on all of its sensors
+ EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+ EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+ } else {
+ // All other subhals should have direct channel disabled for all sensors
+ EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+ EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+ }
+ }
+}
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+ EventFlag* wakelockQueueFlag) {
+ uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
+ wakelockQueue->write(&numEventsUInt32);
+ wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+}
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+ EventFlag* eventQueueFlag) {
+ constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
+ std::vector<Event> events(numEvents);
+ return eventQueue->readBlocking(events.data(), numEvents,
+ static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+ static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+ kReadBlockingTimeout, eventQueueFlag);
+}
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
+ return std::make_unique<EventMessageQueue>(size, true);
+}
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
+ return std::make_unique<WakeupMessageQueue>(size, true);
+}
+
+Event makeProximityEvent() {
+ Event event;
+ event.timestamp = 0xFF00FF00;
+ // This is the sensorhandle of proximity, which is wakeup type
+ event.sensorHandle = 0x00000008;
+ event.sensorType = SensorType::PROXIMITY;
+ event.u = EventPayload();
+ return event;
+}
+
+Event makeAccelerometerEvent() {
+ Event event;
+ event.timestamp = 0xFF00FF00;
+ // This is the sensorhandle of proximity, which is wakeup type
+ event.sensorHandle = 0x00000001;
+ event.sensorType = SensorType::ACCELEROMETER;
+ event.u = EventPayload();
+ return event;
+}
+
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents) {
+ std::vector<Event> events;
+ for (size_t i = 0; i < numEvents; i++) {
+ events.push_back(makeProximityEvent());
+ }
+ return events;
+}
+
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents) {
+ std::vector<Event> events;
+ for (size_t i = 0; i < numEvents; i++) {
+ events.push_back(makeAccelerometerEvent());
+ }
+ return events;
+}
+
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+ std::vector<SensorInfo>& sensors,
+ std::vector<int32_t>& sensorHandles) {
+ for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
+ sensorHandle++) {
+ SensorInfo sensor;
+ // Just set the sensorHandle field to the correct value so as to not have
+ // to compare every field
+ sensor.sensorHandle = sensorHandle;
+ sensors.push_back(sensor);
+ sensorHandles.push_back(sensorHandle);
+ }
+}
+
+} // namespace
diff --git a/sensors/2.0/multihal/tests/fake_subhal/README b/sensors/2.0/multihal/tests/fake_subhal/README
new file mode 100644
index 0000000..ddcc584
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/README
@@ -0,0 +1,19 @@
+This directory contains a modified version of the default implementation
+provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a
+means to verify the multi-HAL 2.0 implementation can successfully load and
+interact with sub-HALs.
+
+This sub-HAL implementation has two macros that can be used to configure support
+for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables
+support for continuous sensors like accel, and gyro whereas the other
+"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the
+light and proximity sensor. A build target is defined for each of these macros,
+but more targets could be added to support both in one sub-HAL or none at all,
+if necessary.
+
+When built, the library will be written to
+out/target/product/<device>/vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so
+
+Take this .so and place it where the multi-HAL config will cause the HalProxy to
+look and then restart the system server with adb shell stop / adb shell start
+to cause the multi-HAL to restart and attempt to load in the sub-HAL.
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
new file mode 100644
index 0000000..de89a00
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Sensor.h"
+
+#include <hardware/sensors.h>
+#include <utils/SystemClock.h>
+
+#include <cmath>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+
+Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : mIsEnabled(false),
+ mSamplingPeriodNs(0),
+ mLastSampleTimeNs(0),
+ mCallback(callback),
+ mMode(OperationMode::NORMAL) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ constexpr float kDefaultMaxDelayUs = 1000 * 1000;
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+ mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+ // Ensure that lock is unlocked before calling mRunThread.join() or a
+ // deadlock will occur.
+ {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mStopThread = true;
+ mIsEnabled = false;
+ mWaitCV.notify_all();
+ }
+ mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+ return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+ samplingPeriodNs =
+ std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+
+ if (mSamplingPeriodNs != samplingPeriodNs) {
+ mSamplingPeriodNs = samplingPeriodNs;
+ // Wake up the 'run' thread to check if a new event should be generated now
+ mWaitCV.notify_all();
+ }
+}
+
+void Sensor::activate(bool enable) {
+ if (mIsEnabled != enable) {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mIsEnabled = enable;
+ mWaitCV.notify_all();
+ }
+}
+
+Result Sensor::flush() {
+ // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+ // one-shot sensor.
+ if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+ return Result::BAD_VALUE;
+ }
+
+ // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+ // to the Event FMQ prior to writing the flush complete event.
+ Event ev;
+ ev.sensorHandle = mSensorInfo.sensorHandle;
+ ev.sensorType = SensorType::META_DATA;
+ ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+ std::vector<Event> evs{ev};
+ mCallback->postEvents(evs, isWakeUpSensor());
+
+ return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+ sensor->run();
+}
+
+void Sensor::run() {
+ std::unique_lock<std::mutex> runLock(mRunMutex);
+ constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+ while (!mStopThread) {
+ if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+ mWaitCV.wait(runLock, [&] {
+ return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+ });
+ } else {
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME, &curTime);
+ int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+ int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+ if (now >= nextSampleTime) {
+ mLastSampleTimeNs = now;
+ nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+ mCallback->postEvents(readEvents(), isWakeUpSensor());
+ }
+
+ mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+ }
+ }
+}
+
+bool Sensor::isWakeUpSensor() {
+ return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 0;
+ event.u.vec3.z = 0;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+ if (mMode != mode) {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mMode = mode;
+ mWaitCV.notify_all();
+ }
+}
+
+bool Sensor::supportsDataInjection() const {
+ return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+ Result result = Result::OK;
+ if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+ // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+ // environment data into the device.
+ } else if (!supportsDataInjection()) {
+ result = Result::INVALID_OPERATION;
+ } else if (mMode == OperationMode::DATA_INJECTION) {
+ mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+ } else {
+ result = Result::BAD_VALUE;
+ }
+ return result;
+}
+
+OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(sensorHandle, callback), mPreviousEventSet(false) {
+ mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
+}
+
+void OnChangeSensor::activate(bool enable) {
+ Sensor::activate(enable);
+ if (!enable) {
+ mPreviousEventSet = false;
+ }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+ std::vector<Event> events = Sensor::readEvents();
+ std::vector<Event> outputEvents;
+
+ for (auto iter = events.begin(); iter != events.end(); ++iter) {
+ Event ev = *iter;
+ if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+ outputEvents.push_back(ev);
+ mPreviousEvent = ev;
+ mPreviousEventSet = true;
+ }
+ }
+ return outputEvents;
+}
+
+ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(sensorHandle, callback) {
+ mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Accel Sensor";
+ mSensorInfo.type = SensorType::ACCELEROMETER;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
+ mSensorInfo.maxRange = 78.4f; // +/- 8g
+ mSensorInfo.resolution = 1.52e-5;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 20 * 1000; // microseconds
+ mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
+}
+
+std::vector<Event> AccelSensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 0;
+ event.u.vec3.z = -9.815;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Pressure Sensor";
+ mSensorInfo.type = SensorType::PRESSURE;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
+ mSensorInfo.maxRange = 1100.0f; // hPa
+ mSensorInfo.resolution = 0.005f; // hPa
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 100 * 1000; // microseconds
+}
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Magnetic Field Sensor";
+ mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
+ mSensorInfo.maxRange = 1300.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 20 * 1000; // microseconds
+}
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Light Sensor";
+ mSensorInfo.type = SensorType::LIGHT;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
+ mSensorInfo.maxRange = 43000.0f;
+ mSensorInfo.resolution = 10.0f;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 200 * 1000; // microseconds
+}
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Proximity Sensor";
+ mSensorInfo.type = SensorType::PROXIMITY;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
+ mSensorInfo.maxRange = 5.0f;
+ mSensorInfo.resolution = 1.0f;
+ mSensorInfo.power = 0.012f; // mA
+ mSensorInfo.minDelay = 200 * 1000; // microseconds
+ mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
+}
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Gyro Sensor";
+ mSensorInfo.type = SensorType::GYROSCOPE;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
+ mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+ mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 2.5f * 1000; // microseconds
+}
+
+std::vector<Event> GyroSensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 0;
+ event.u.vec3.z = 0;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Ambient Temp Sensor";
+ mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
+ mSensorInfo.maxRange = 80.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 40 * 1000; // microseconds
+}
+
+DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : ContinuousSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Device Temp Sensor";
+ mSensorInfo.type = SensorType::TEMPERATURE;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
+ mSensorInfo.maxRange = 80.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 40 * 1000; // microseconds
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+ ISensorsEventCallback* callback)
+ : OnChangeSensor(sensorHandle, callback) {
+ mSensorInfo.name = "Relative Humidity Sensor";
+ mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+ mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
+ mSensorInfo.maxRange = 100.0f;
+ mSensorInfo.resolution = 0.1f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 40 * 1000; // microseconds
+}
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
new file mode 100644
index 0000000..60f5d3d
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+class ISensorsEventCallback {
+ public:
+ virtual ~ISensorsEventCallback(){};
+ virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+ public:
+ Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+ virtual ~Sensor();
+
+ const SensorInfo& getSensorInfo() const;
+ void batch(int32_t samplingPeriodNs);
+ virtual void activate(bool enable);
+ Result flush();
+
+ void setOperationMode(OperationMode mode);
+ bool supportsDataInjection() const;
+ Result injectEvent(const Event& event);
+
+ protected:
+ void run();
+ virtual std::vector<Event> readEvents();
+ static void startThread(Sensor* sensor);
+
+ bool isWakeUpSensor();
+
+ bool mIsEnabled;
+ int64_t mSamplingPeriodNs;
+ int64_t mLastSampleTimeNs;
+ SensorInfo mSensorInfo;
+
+ std::atomic_bool mStopThread;
+ std::condition_variable mWaitCV;
+ std::mutex mRunMutex;
+ std::thread mRunThread;
+
+ ISensorsEventCallback* mCallback;
+
+ OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+ public:
+ OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ virtual void activate(bool enable) override;
+
+ protected:
+ virtual std::vector<Event> readEvents() override;
+
+ protected:
+ Event mPreviousEvent;
+ bool mPreviousEventSet;
+};
+
+class ContinuousSensor : public Sensor {
+ public:
+ ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AccelSensor : public ContinuousSensor {
+ public:
+ AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ std::vector<Event> readEvents() override;
+};
+
+class GyroSensor : public ContinuousSensor {
+ public:
+ GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ std::vector<Event> readEvents() override;
+};
+
+class DeviceTempSensor : public ContinuousSensor {
+ public:
+ DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public ContinuousSensor {
+ public:
+ PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public ContinuousSensor {
+ public:
+ MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+ public:
+ AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class LightSensor : public OnChangeSensor {
+ public:
+ LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class ProximitySensor : public OnChangeSensor {
+ public:
+ ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+ public:
+ RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
new file mode 100644
index 0000000..ff5ff38
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsSubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+ static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+ static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
+ subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+ static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
+#else
+ static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
+#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+ *version = SUB_HAL_2_0_VERSION;
+ return &subHal;
+}
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
+
+SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
+
+// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ sensors.push_back(sensor.second->getSensorInfo());
+ }
+
+ _hidl_cb(sensors);
+ return Void();
+}
+
+Return<Result> SensorsSubHal::setOperationMode(OperationMode mode) {
+ for (auto sensor : mSensors) {
+ sensor.second->setOperationMode(mode);
+ }
+ mCurrentOperationMode = mode;
+ return Result::OK;
+}
+
+Return<Result> SensorsSubHal::activate(int32_t sensorHandle, bool enabled) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->activate(enabled);
+ return Result::OK;
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t /* maxReportLatencyNs */) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->batch(samplingPeriodNs);
+ return Result::OK;
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::flush(int32_t sensorHandle) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->flush();
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::injectSensorData(const Event& event) {
+ auto sensor = mSensors.find(event.sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->injectEvent(event);
+ }
+
+ return Result::BAD_VALUE;
+}
+
+Return<void> SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */,
+ registerDirectChannel_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+ return Return<void>();
+}
+
+Return<Result> SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) {
+ return Result::INVALID_OPERATION;
+}
+
+Return<void> SensorsSubHal::configDirectReport(int32_t /* sensorHandle */,
+ int32_t /* channelHandle */, RateLevel /* rate */,
+ configDirectReport_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+ return Return<void>();
+}
+
+Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+ if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+ ALOGE("%s: missing fd for writing", __FUNCTION__);
+ return Void();
+ }
+
+ FILE* out = fdopen(dup(fd->data[0]), "w");
+
+ if (args.size() != 0) {
+ fprintf(out,
+ "Note: sub-HAL %s currently does not support args. Input arguments are "
+ "ignored.\n",
+ getName().c_str());
+ }
+
+ std::ostringstream stream;
+ stream << "Available sensors:" << std::endl;
+ for (auto sensor : mSensors) {
+ SensorInfo info = sensor.second->getSensorInfo();
+ stream << "Name: " << info.name << std::endl;
+ stream << "Min delay: " << info.minDelay << std::endl;
+ stream << "Flags: " << info.flags << std::endl;
+ }
+ stream << std::endl;
+
+ fprintf(out, "%s", stream.str().c_str());
+
+ fclose(out);
+ return Return<void>();
+}
+
+Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
+ mCallback = halProxyCallback;
+ setOperationMode(OperationMode::NORMAL);
+ return Result::OK;
+}
+
+void SensorsSubHal::postEvents(const std::vector<Event>& events, bool wakeup) {
+ ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
+ mCallback->postEvents(events, std::move(wakelock));
+}
+
+ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
+ AddSensor<AccelSensor>();
+ AddSensor<GyroSensor>();
+ AddSensor<MagnetometerSensor>();
+ AddSensor<PressureSensor>();
+ AddSensor<DeviceTempSensor>();
+}
+
+OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
+ AddSensor<AmbientTempSensor>();
+ AddSensor<LightSensor>();
+ AddSensor<ProximitySensor>();
+ AddSensor<RelativeHumiditySensor>();
+}
+
+AllSensorsSubHal::AllSensorsSubHal() {
+ AddSensor<AccelSensor>();
+ AddSensor<GyroSensor>();
+ AddSensor<MagnetometerSensor>();
+ AddSensor<PressureSensor>();
+ AddSensor<DeviceTempSensor>();
+ AddSensor<AmbientTempSensor>();
+ AddSensor<LightSensor>();
+ AddSensor<ProximitySensor>();
+ AddSensor<RelativeHumiditySensor>();
+}
+
+Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
+ return Result::BAD_VALUE;
+}
+
+Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ SensorInfo sensorInfo = sensor.second->getSensorInfo();
+ sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
+ sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
+ sensors.push_back(sensorInfo);
+ }
+ _hidl_cb(sensors);
+ return Void();
+}
+
+Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ SensorInfo sensorInfo = sensor.second->getSensorInfo();
+ sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+ sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
+ sensors.push_back(sensorInfo);
+ }
+ _hidl_cb(sensors);
+ return Void();
+}
+
+void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
+ const std::vector<SensorInfo>& sensorsAdded) {
+ mCallback->onDynamicSensorsConnected(sensorsAdded);
+}
+
+void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
+ const std::vector<int32_t>& sensorHandlesRemoved) {
+ mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
+}
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
new file mode 100644
index 0000000..c1e3647
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SubHal.h"
+
+#include "Sensor.h"
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
+
+/**
+ * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
+ * See the README file for more details on how this class can be used for testing.
+ */
+class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback {
+ using Event = ::android::hardware::sensors::V1_0::Event;
+ using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+ using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+
+ public:
+ SensorsSubHal();
+
+ // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+ virtual Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+ virtual Return<Result> setOperationMode(OperationMode mode) override;
+
+ OperationMode getOperationMode() const { return mCurrentOperationMode; }
+
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ Return<Result> flush(int32_t sensorHandle) override;
+
+ Return<Result> injectSensorData(const Event& event) override;
+
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) override;
+
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+ // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
+ const std::string getName() override {
+#ifdef SUB_HAL_NAME
+ return SUB_HAL_NAME;
+#else // SUB_HAL_NAME
+ return "FakeSubHal";
+#endif // SUB_HAL_NAME
+ }
+
+ Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
+
+ // Method from ISensorsEventCallback.
+ void postEvents(const std::vector<Event>& events, bool wakeup) override;
+
+ protected:
+ template <class SensorType>
+ void AddSensor() {
+ std::shared_ptr<SensorType> sensor =
+ std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+ mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+ }
+
+ /**
+ * A map of the available sensors
+ */
+ std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+ /**
+ * Callback used to communicate to the HalProxy when dynamic sensors are connected /
+ * disconnected, sensor events need to be sent to the framework, and when a wakelock should be
+ * acquired.
+ */
+ sp<IHalProxyCallback> mCallback;
+
+ private:
+ /**
+ * The current operation mode of the multihal framework. Ensures that all subhals are set to
+ * the same operation mode.
+ */
+ OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+ /**
+ * The next available sensor handle
+ */
+ int32_t mNextHandle;
+};
+
+// SubHal that has continuous sensors for testing purposes.
+class ContinuousSensorsSubHal : public SensorsSubHal {
+ public:
+ ContinuousSensorsSubHal();
+};
+
+// SubHal that has on-change sensors for testing purposes.
+class OnChangeSensorsSubHal : public SensorsSubHal {
+ public:
+ OnChangeSensorsSubHal();
+};
+
+// SubHal that has both continuous and on-change sensors for testing purposes.
+class AllSensorsSubHal : public SensorsSubHal {
+ public:
+ AllSensorsSubHal();
+};
+
+class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal {
+ public:
+ Return<Result> setOperationMode(OperationMode mode) override;
+};
+
+class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+ public:
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+ public:
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
+ public:
+ void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
+ void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
+};
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android