diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp index 1fbc787157..5aa3b3d22b 100644 --- a/sensors/2.0/multihal/HalProxy.cpp +++ b/sensors/2.0/multihal/HalProxy.cpp @@ -38,6 +38,18 @@ using ::android::hardware::sensors::V2_0::EventQueueFlagBits; typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*); +/** + * 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. + */ +uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { + return sensorHandle | (subHalIndex << 24); +} + HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); @@ -206,15 +218,45 @@ Return HalProxy::debug(const hidl_handle& /* fd */, const hidl_vec(); } -Return HalProxy::onDynamicSensorsConnected( - const hidl_vec& /* dynamicSensorsAdded */, int32_t /* subHalIndex */) { - // TODO: Map the SensorInfo to the global list and then invoke the framework's callback. +Return HalProxy::onDynamicSensorsConnected(const hidl_vec& dynamicSensorsAdded, + int32_t subHalIndex) { + std::vector sensors; + { + std::lock_guard 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(); } Return HalProxy::onDynamicSensorsDisconnected( - const hidl_vec& /* dynamicSensorHandlesRemoved */, int32_t /* subHalIndex */) { - // TODO: Unmap the SensorInfo from the global list and then invoke the framework's callback. + const hidl_vec& dynamicSensorHandlesRemoved, int32_t subHalIndex) { + // TODO: Block this call until all pending events are flushed from queue + std::vector sensorHandles; + { + std::lock_guard 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(); } @@ -264,7 +306,7 @@ void HalProxy::initializeSensorList() { ISensorsSubHal* subHal = mSubHalList[subHalIndex]; auto result = subHal->getSensorsList([&](const auto& list) { for (SensorInfo sensor : list) { - if ((sensor.sensorHandle & kSensorHandleSubHalIndexMask) != 0) { + if (!subHalIndexIsClear(sensor.sensorHandle)) { ALOGE("SubHal sensorHandle's first byte was not 0"); } else { ALOGV("Loaded sensor: %s", sensor.name.c_str()); @@ -389,6 +431,10 @@ uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } +bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) { + return (sensorHandle & kSensorHandleSubHalIndexMask) == 0; +} + void HalProxyCallback::postEvents(const std::vector& events, ScopedWakelock wakelock) { (void)wakelock; size_t numWakeupEvents; @@ -418,7 +464,7 @@ std::vector HalProxyCallback::processEvents(const std::vector& eve std::vector eventsOut; *numWakeupEvents = 0; for (Event event : events) { - event.sensorHandle = setSubHalIndex(event.sensorHandle); + event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); eventsOut.push_back(event); if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { @@ -428,10 +474,6 @@ std::vector HalProxyCallback::processEvents(const std::vector& eve return eventsOut; } -uint32_t HalProxyCallback::setSubHalIndex(uint32_t sensorHandle) const { - return sensorHandle | mSubHalIndex << 24; -} - } // namespace implementation } // namespace V2_0 } // namespace sensors diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h index ae4b2c53c6..47571a6368 100644 --- a/sensors/2.0/multihal/include/HalProxy.h +++ b/sensors/2.0/multihal/include/HalProxy.h @@ -176,6 +176,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ std::map mSensors; + //! Map of the dynamic sensors that have been added to halproxy. + std::map mDynamicSensors; + //! The current operation mode for all subhals. OperationMode mCurrentOperationMode = OperationMode::NORMAL; @@ -212,6 +215,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The bool indicating whether to end the pending writes background thread or not bool mPendingWritesRun = true; + //! The mutex protecting access to the dynamic sensors added and removed methods. + std::mutex mDynamicSensorsMutex; + /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. @@ -271,6 +277,13 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { * @return The modified version of the sensor handle. */ static uint32_t clearSubHalIndex(uint32_t sensorHandle); + + /** + * @param sensorHandle The sensor handle to modify. + * + * @return true if subHalIndex byte of sensorHandle is zeroed. + */ + static bool subHalIndexIsClear(uint32_t sensorHandle); }; /** @@ -303,8 +316,6 @@ class HalProxyCallback : public IHalProxyCallback { std::vector processEvents(const std::vector& events, size_t* numWakeupEvents) const; - - uint32_t setSubHalIndex(uint32_t sensorHandle) const; }; } // namespace implementation diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp index 61fb14c38f..c8fbb730f6 100644 --- a/sensors/2.0/multihal/tests/HalProxy_test.cpp +++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp @@ -23,6 +23,7 @@ #include "SensorsSubHal.h" #include +#include #include #include @@ -38,6 +39,7 @@ using ::android::hardware::sensors::V1_0::SensorType; using ::android::hardware::sensors::V2_0::ISensorsCallback; 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; @@ -68,6 +70,34 @@ class SensorsCallback : public ISensorsCallback { } }; +// The sensors callback that expects a variable list of sensors to be added +class TestSensorsCallback : public ISensorsCallback { + public: + Return onDynamicSensorsConnected( + const hidl_vec& dynamicSensorsAdded) override { + mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(), + dynamicSensorsAdded.end()); + return Return(); + } + + Return onDynamicSensorsDisconnected( + const hidl_vec& dynamicSensorHandlesRemoved) override { + mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(), + dynamicSensorHandlesRemoved.begin(), + dynamicSensorHandlesRemoved.end()); + return Return(); + } + + const std::vector& getSensorsConnected() const { return mSensorsConnected; } + const std::vector& getSensorHandlesDisconnected() const { + return mSensorHandlesDisconnected; + } + + private: + std::vector mSensorsConnected; + std::vector mSensorHandlesDisconnected; +}; + // Helper declarations follow /** @@ -129,6 +159,20 @@ std::vector makeMultipleProximityEvents(size_t numEvents); */ std::vector 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& sensors, + std::vector& sensorHandles); + // Tests follow TEST(HalProxyTest, GetSensorsListOneSubHalTest) { AllSensorsSubHal subHal; @@ -396,6 +440,83 @@ TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) { // If this TEST completes then it was a success, if it hangs we will see a crash } +TEST(HalProxyTest, DynamicSensorsConnectedTest) { + constexpr size_t kNumSensors = 3; + AddAndRemoveDynamicSensorsSubHal subHal; + std::vector subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = std::make_unique(0, true); + std::unique_ptr wakeLockQueue = + std::make_unique(0, true); + + std::vector sensorsToConnect; + std::vector sensorHandlesToExpect; + makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect, + sensorHandlesToExpect); + + TestSensorsCallback* callback = new TestSensorsCallback(); + ::android::sp callbackPtr = callback; + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); + subHal.addDynamicSensors(sensorsToConnect); + + std::vector 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 subHals{&subHal}; + HalProxy proxy(subHals); + std::unique_ptr eventQueue = std::make_unique(0, true); + std::unique_ptr wakeLockQueue = + std::make_unique(0, true); + + std::vector sensorsToConnect; + std::vector sensorHandlesToExpect; + makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect, + sensorHandlesToExpect); + + std::vector nonDynamicSensorHandles; + for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) { + nonDynamicSensorHandles.push_back(sensorHandle); + } + + std::set nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(), + nonDynamicSensorHandles.end()); + + std::vector sensorHandlesToAttemptToRemove; + sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(), + sensorHandlesToExpect.begin(), + sensorHandlesToExpect.end()); + sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(), + nonDynamicSensorHandles.begin(), + nonDynamicSensorHandles.end()); + + TestSensorsCallback* callback = new TestSensorsCallback(); + ::android::sp callbackPtr = callback; + proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr); + subHal.addDynamicSensors(sensorsToConnect); + subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove); + + std::vector 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()); + } +} + // Helper implementations follow void testSensorsListFromProxyAndSubHal(const std::vector& proxySensorsList, const std::vector& subHalSensorsList) { @@ -463,4 +584,18 @@ std::vector makeMultipleAccelerometerEvents(size_t numEvents) { return events; } +void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size, + std::vector& sensors, + std::vector& sensorHandles) { + for (int32_t sensorHandle = start; sensorHandle < start + static_cast(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/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp index d581c49a32..cf3ae7560d 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp @@ -221,6 +221,16 @@ Return DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensors return Void(); } +void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors( + const std::vector& sensorsAdded) { + mCallback->onDynamicSensorsConnected(sensorsAdded); +} + +void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors( + const std::vector& sensorHandlesRemoved) { + mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved); +} + } // 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 61caa2c39e..c1e36472cf 100644 --- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h +++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h @@ -98,13 +98,6 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { */ 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 @@ -112,6 +105,13 @@ class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { */ sp 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 */ @@ -151,6 +151,12 @@ class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal { Return getSensorsList(getSensorsList_cb _hidl_cb) override; }; +class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal { + public: + void addDynamicSensors(const std::vector& sensorsAdded); + void removeDynamicSensors(const std::vector& sensorHandlesAdded); +}; + } // namespace implementation } // namespace subhal } // namespace V2_0