From 7a7235461f19e4ce5a19e34271e4efd3c6d49a70 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 29 Aug 2019 15:47:50 -0700 Subject: [PATCH] MultiHal 2.0 - setOperationMode and init direct channel flags Implement setOperationMode method of HalProxy object and initialized the direct channel flag for the sensors list. Also create some unit tests to test both of these new additions in HalProxy_test.cpp. Bug: 136511617 Test: Tested using unit tests and tested on device with both fake subhals Change-Id: I4e39ca0e94b3e109706d628612d1db9c98aca053 --- sensors/2.0/multihal/Android.bp | 1 + sensors/2.0/multihal/HalProxy.cpp | 55 ++++++-- sensors/2.0/multihal/include/HalProxy.h | 19 ++- sensors/2.0/multihal/service.cpp | 2 - sensors/2.0/multihal/tests/HalProxy_test.cpp | 119 ++++++++++++++++-- .../tests/fake_subhal/SensorsSubHal.cpp | 29 +++++ .../tests/fake_subhal/SensorsSubHal.h | 41 ++++-- 7 files changed, 233 insertions(+), 33 deletions(-) diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp index 44dddfd4e9..697bf9e117 100644 --- a/sensors/2.0/multihal/Android.bp +++ b/sensors/2.0/multihal/Android.bp @@ -45,6 +45,7 @@ cc_binary { ], init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"], vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"], + cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } cc_library_headers { diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index d8bde8354c..28dae93ebd 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -69,8 +69,8 @@ class SensorsCallbackProxy : public ISensorsCallback { }; HalProxy::HalProxy() { - const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf"; - initializeSubHalListFromConfigFile(kMultiHalConfigFilePath); + const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; + initializeSubHalListFromConfigFile(kMultiHalConfigFile); initializeSensorList(); } @@ -88,9 +88,27 @@ Return HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { return Void(); } -Return HalProxy::setOperationMode(OperationMode /* mode */) { - // TODO: Proxy API call to all sub-HALs and return appropriate result. - return Result::INVALID_OPERATION; +Return 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 HalProxy::activate(int32_t sensorHandle, bool enabled) { @@ -190,27 +208,27 @@ Return HalProxy::onDynamicSensorsDisconnected( void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) { std::ifstream subHalConfigStream(configFileName); if (!subHalConfigStream) { - LOG_FATAL("Failed to load subHal config file: %s", configFileName); + 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) { - LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str()); + ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str()); } else { SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr = (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal"); if (sensorsHalGetSubHalPtr == nullptr) { - LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s", - subHalLibraryFile.c_str()); + ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s", + subHalLibraryFile.c_str()); } else { std::function sensorsHalGetSubHal = *sensorsHalGetSubHalPtr; uint32_t version; ISensorsSubHal* subHal = sensorsHalGetSubHal(&version); if (version != SUB_HAL_2_0_VERSION) { - LOG_FATAL("SubHal version was not 2.0 for library: %s", - subHalLibraryFile.c_str()); + 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); @@ -231,6 +249,7 @@ void HalProxy::initializeSensorList() { } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); sensor.sensorHandle |= (subHalIndex << 24); + setDirectChannelFlags(&sensor, subHal); mSensorList.push_back(sensor); } } @@ -241,6 +260,20 @@ void HalProxy::initializeSensorList() { } } +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(uint32_t sensorHandle) { return mSubHalList[static_cast(sensorHandle >> 24)]; } diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index b0261c8c7d..24b5081591 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -125,10 +125,16 @@ class HalProxy : public ISensors { * 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. + * the remaining bytes are generated by the subhal to identify the sensor. */ std::vector mSensorList; + //! The current operation mode for all subhals. + OperationMode mCurrentOperationMode = OperationMode::NORMAL; + + //! The single subHal that supports directChannel reporting. + ISensorsSubHal* mDirectChannelSubHal = nullptr; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -141,6 +147,17 @@ class HalProxy : public ISensors { */ void initializeSensorList(); + /** + * 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. diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp index 995cf3cbe0..ef77048020 100644 --- a/sensors/2.0/multihal/service.cpp +++ b/sensors/2.0/multihal/service.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.sensors@2.0-service" - #include #include #include diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 28004d0d32..1e1f9e9e44 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -15,33 +15,56 @@ #include +#include + #include "HalProxy.h" #include "SensorsSubHal.h" #include +namespace { + +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::implementation::HalProxy; 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; -// TODO: Add more interesting tests such as -// - verify setOperationMode invokes all subhals -// - verify if a subhal fails to change operation mode, that state is reset properly -// - Available sensors are obtained during initialization -// -// You can run this suite using "atest android.hardware.sensors@2.0-halproxy-unit-tests". -// -// See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info -// on how tests are set up and for information on the gtest framework itself. +using ::android::hardware::sensors::V2_0::subhal::implementation:: + SetOperationModeFailingSensorsSubHal; // 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& proxySensorsList, const std::vector& 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& sensorsList, + size_t enabledSubHalIndex); + // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { AllSensorsSubHal subHal; @@ -76,6 +99,63 @@ TEST(HalProxyTest, GetSensorsListTwoSubHalTest) { testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList); } +TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) { + ContinuousSensorsSubHal subHal1; + OnChangeSensorsSubHal subHal2; + + std::vector 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 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 fakeSubHals{&subHal1, &subHal2}; + HalProxy proxy(fakeSubHals); + + proxy.getSensorsList([&](const auto& sensorsList) { + testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0); + }); +} + +TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) { + DoesNotSupportDirectChannelSensorsSubHal subHal1; + AllSupportDirectChannelSensorsSubHal subHal2, subHal3; + std::vector fakeSubHals{&subHal1, &subHal2, &subHal3}; + HalProxy proxy(fakeSubHals); + + proxy.getSensorsList([&](const auto& sensorsList) { + testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1); + }); +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -88,4 +168,23 @@ void testSensorsListFromProxyAndSubHal(const std::vector& proxySenso EXPECT_EQ(proxySensor.type, subHalSensor.type); EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle); } -} \ No newline at end of file +} + +void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector& sensorsList, + size_t enabledSubHalIndex) { + for (const SensorInfo& sensor : sensorsList) { + size_t subHalIndex = static_cast(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); + } + } +} + +} // namespace diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index fe471616c5..d581c49a32 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -68,6 +68,7 @@ Return SensorsSubHal::setOperationMode(OperationMode mode) { for (auto sensor : mSensors) { sensor.second->setOperationMode(mode); } + mCurrentOperationMode = mode; return Result::OK; } @@ -192,6 +193,34 @@ AllSensorsSubHal::AllSensorsSubHal() { AddSensor(); } +Return SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) { + return Result::BAD_VALUE; +} + +Return AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector 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 DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) { + std::vector sensors; + for (const auto& sensor : mSensors) { + SensorInfo sensorInfo = sensor.second->getSensorInfo(); + sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL); + sensorInfo.flags &= ~static_cast(V1_0::SensorFlagBits::MASK_DIRECT_REPORT); + sensors.push_back(sensorInfo); + } + _hidl_cb(sensors); + return Void(); +} + } // namespace implementation } // namespace subhal } // namespace V2_0 diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h index d94d73d536..61caa2c39e 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h @@ -29,6 +29,8 @@ 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; /** @@ -37,18 +39,18 @@ using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback; */ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { 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 SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo; public: SensorsSubHal(); // Methods from ::android::hardware::sensors::V2_0::ISensors follow. - Return getSensorsList(getSensorsList_cb _hidl_cb) override; + virtual Return getSensorsList(getSensorsList_cb _hidl_cb) override; - Return setOperationMode(OperationMode mode) override; + virtual Return setOperationMode(OperationMode mode) override; + + OperationMode getOperationMode() const { return mCurrentOperationMode; } Return activate(int32_t sensorHandle, bool enabled) override; @@ -91,7 +93,18 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { mSensors[sensor->getSensorInfo().sensorHandle] = sensor; } + /** + * A map of the available sensors + */ + std::map> mSensors; + private: + /** + * The current operation mode of the multihal framework. Ensures that all subhals are set to + * the same operation mode. + */ + OperationMode mCurrentOperationMode = OperationMode::NORMAL; + /** * 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 @@ -99,11 +112,6 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { */ sp mCallback; - /** - * A map of the available sensors - */ - std::map> mSensors; - /** * The next available sensor handle */ @@ -128,6 +136,21 @@ class AllSensorsSubHal : public SensorsSubHal { AllSensorsSubHal(); }; +class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal { + public: + Return setOperationMode(OperationMode mode) override; +}; + +class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { + public: + Return getSensorsList(getSensorsList_cb _hidl_cb) override; +}; + +class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { + public: + Return getSensorsList(getSensorsList_cb _hidl_cb) override; +}; + } // namespace implementation } // namespace subhal } // namespace V2_0