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