Loading sensors/2.0/multihal/Android.bp +4 −1 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ cc_defaults { "libpower", "libutils", ], cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } cc_binary { Loading @@ -45,7 +46,6 @@ 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 { Loading @@ -66,4 +66,7 @@ cc_test_library { export_header_lib_headers: [ "android.hardware.sensors@2.0-multihal.header", ], shared_libs: [ "libutils", ], } sensors/2.0/multihal/HalProxy.cpp +118 −37 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <dlfcn.h> #include <cinttypes> #include <fstream> #include <functional> #include <thread> Loading @@ -35,6 +36,9 @@ 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*); Loading @@ -53,23 +57,23 @@ uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); initializeSubHalCallbacksAndSensorList(); init(); } HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) { initializeSubHalCallbacksAndSensorList(); init(); } HalProxy::~HalProxy() { { std::lock_guard<std::mutex> lockGuard(mEventQueueWriteMutex); mPendingWritesRun = false; mThreadsRun.store(false); mWakelockCV.notify_one(); mEventQueueWriteCV.notify_one(); } if (mPendingWritesThread.joinable()) { mPendingWritesThread.join(); } // TODO: Cleanup wakeup thread once it is implemented if (mWakelockThread.joinable()) { mWakelockThread.join(); } } Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { Loading Loading @@ -140,7 +144,7 @@ Return<Result> HalProxy::initialize( } mPendingWritesThread = std::thread(startPendingWritesThread, this); // TODO: start threads to read wake locks. mWakelockThread = std::thread(startWakelockThread, this); for (size_t i = 0; i < mSubHalList.size(); i++) { auto subHal = mSubHalList[i]; Loading Loading @@ -322,7 +326,7 @@ void HalProxy::initializeSensorList() { } } void HalProxy::initializeSubHalCallbacksAndSensorList() { void HalProxy::init() { initializeSubHalCallbacks(); initializeSensorList(); } Loading @@ -334,11 +338,12 @@ void HalProxy::startPendingWritesThread(HalProxy* halProxy) { void HalProxy::handlePendingWrites() { // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one. std::unique_lock<std::mutex> lock(mEventQueueWriteMutex); while (mPendingWritesRun) { while (mThreadsRun.load()) { mEventQueueWriteCV.wait( lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; }); if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) { std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front(); 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(); Loading @@ -348,10 +353,16 @@ void HalProxy::handlePendingWrites() { pendingWriteEvents.data(), numToWrite, static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ), static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS), kWakelockTimeoutNs, mEventQueueFlag)) { kPendingWriteTimeoutNs, mEventQueueFlag)) { ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite); if (numWakeupEvents > 0) { if (pendingWriteEvents.size() > eventQueueSize) { decrementRefCountAndMaybeReleaseWakelock( countNumWakeupEvents(pendingWriteEvents, eventQueueSize)); } else { mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS)); decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents); } } } lock.lock(); if (pendingWriteEvents.size() > eventQueueSize) { Loading @@ -366,9 +377,60 @@ void HalProxy::handlePendingWrites() { } } void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) { 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) { Loading @@ -384,28 +446,37 @@ void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) { if (numToWrite < events.size()) { // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework // stalls mPendingWriteEventsQueue.push( std::vector<Event>(events.begin() + numToWrite, events.end())); std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end()); mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents}); mEventQueueWriteCV.notify_one(); } } // TODO: Implement the wakelock timeout in these next two methods. Also pass in the subhal // index for better tracking. void HalProxy::incrementRefCountAndMaybeAcquireWakelock() { std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex); 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); acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName); mWakelockCV.notify_one(); } mWakelockRefCount++; mWakelockTimeoutStartTime = getTimeNow(); mWakelockRefCount += delta; if (timeoutStart != nullptr) { *timeoutStart = mWakelockTimeoutStartTime; } return true; } void HalProxy::decrementRefCountAndMaybeReleaseWakelock() { std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex); mWakelockRefCount--; 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); release_wake_lock(kWakelockName); } } Loading @@ -427,6 +498,17 @@ ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { return mSubHalList[static_cast<size_t>(sensorHandle >> 24)]; } 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; } uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } Loading @@ -436,7 +518,7 @@ bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) { } void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) { (void)wakelock; if (events.empty() || !mHalProxy->areThreadsRunning()) return; size_t numWakeupEvents; std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents); if (numWakeupEvents > 0) { Loading @@ -450,8 +532,7 @@ void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelo " w/ index %zu.", mSubHalIndex); } mHalProxy->postEventsToMessageQueue(processedEvents); mHalProxy->postEventsToMessageQueue(events, numWakeupEvents, std::move(wakelock)); } ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { Loading @@ -461,13 +542,13 @@ ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events, size_t* numWakeupEvents) const { std::vector<Event> eventsOut; *numWakeupEvents = 0; std::vector<Event> eventsOut; for (Event event : events) { event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); eventsOut.push_back(event); if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { (*numWakeupEvents)++; } } Loading sensors/2.0/multihal/ScopedWakelock.cpp +8 −4 Original line number Diff line number Diff line Loading @@ -22,18 +22,22 @@ 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) { // TODO: Move this implementation into HalProxy object instead if (mLocked) { mRefCounter->incrementRefCountAndMaybeAcquireWakelock(); mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs); } } ScopedWakelock::~ScopedWakelock() { // TODO: Move this implementation into HalProxy object instead if (mLocked) { mRefCounter->decrementRefCountAndMaybeReleaseWakelock(); mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs); } } Loading sensors/2.0/multihal/include/HalProxy.h +86 −38 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ #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> Loading @@ -30,6 +32,7 @@ #include <mutex> #include <queue> #include <thread> #include <utility> namespace android { namespace hardware { Loading Loading @@ -100,45 +103,41 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex); // Below methods follow IScopedWakelockRefCounter /** * Increment ref count and maybe acquire wakelock. */ void incrementRefCountAndMaybeAcquireWakelock() override; /** * Decrement ref count and maybe release wakelock. */ void decrementRefCountAndMaybeReleaseWakelock() override; // 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 5 second timeout. * 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); void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents, ScopedWakelock wakelock); /** * Get the SensorInfo object associated with the sensorHandle. * Get the sensor info associated with that sensorHandle. * * @param sensorHandle The sensorHandle for the sensor. * @param sensorHandle The sensor handle. * * @return The sensor info for the sensor. * @return The sensor info object in the mapping. */ const SensorInfo& getSensorInfo(uint32_t sensorHandle) const { return mSensors.at(sensorHandle); } const SensorInfo& getSensorInfo(uint32_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>; const char* kWakeLockName = "SensorsHAL_WAKEUP"; /** * The Event FMQ where sensor events are written */ Loading Loading @@ -185,23 +184,17 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The single subHal that supports directChannel reporting. ISensorsSubHal* mDirectChannelSubHal = nullptr; //! The mutex for the event queue. std::mutex mEventQueueMutex; //! The timeout for each pending write on background thread for events. static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; //! The scoped wakelock ref count. size_t mWakelockRefCount = 0; //! The mutex guarding the mWakelockRefCount variable std::mutex mWakelockRefCountMutex; 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 uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; //! The events that were not able to be written to fmq right away std::queue<std::vector<Event>> mPendingWriteEventsQueue; /** * 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; Loading @@ -212,12 +205,32 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The thread object ptr that handles pending writes std::thread mPendingWritesThread; //! The bool indicating whether to end the pending writes background thread or not bool mPendingWritesRun = true; //! 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 = "SensorsMultiHal"; /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. Loading @@ -236,9 +249,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { void initializeSensorList(); /** * Calls the above two helper methods which are shared in both ctors. * Calls the helper methods that all ctors use. */ void initializeSubHalCallbacksAndSensorList(); void init(); /** * Starts the thread that handles pending writes to event fmq. Loading @@ -250,6 +263,31 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! 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 Loading @@ -269,6 +307,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ ISensorsSubHal* getSubHalForSensorHandle(uint32_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. * Loading sensors/2.0/multihal/include/ScopedWakelock.h +31 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ #pragma once #include <mutex> #include <android/hardware/sensors/2.0/types.h> namespace android { namespace hardware { Loading @@ -24,10 +24,36 @@ namespace sensors { namespace V2_0 { namespace implementation { class IScopedWakelockRefCounter { 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: virtual void incrementRefCountAndMaybeAcquireWakelock() = 0; virtual void decrementRefCountAndMaybeReleaseWakelock() = 0; /** * 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(){}; }; Loading Loading @@ -64,6 +90,7 @@ class ScopedWakelock { private: friend class HalProxyCallback; IScopedWakelockRefCounter* mRefCounter; int64_t mCreatedAtTimeNs; bool mLocked; ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked); ScopedWakelock(const ScopedWakelock&) = delete; Loading Loading
sensors/2.0/multihal/Android.bp +4 −1 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ cc_defaults { "libpower", "libutils", ], cflags: ["-DLOG_TAG=\"SensorsMultiHal\""], } cc_binary { Loading @@ -45,7 +46,6 @@ 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 { Loading @@ -66,4 +66,7 @@ cc_test_library { export_header_lib_headers: [ "android.hardware.sensors@2.0-multihal.header", ], shared_libs: [ "libutils", ], }
sensors/2.0/multihal/HalProxy.cpp +118 −37 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <dlfcn.h> #include <cinttypes> #include <fstream> #include <functional> #include <thread> Loading @@ -35,6 +36,9 @@ 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*); Loading @@ -53,23 +57,23 @@ uint32_t setSubHalIndex(uint32_t sensorHandle, size_t subHalIndex) { HalProxy::HalProxy() { const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf"; initializeSubHalListFromConfigFile(kMultiHalConfigFile); initializeSubHalCallbacksAndSensorList(); init(); } HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) { initializeSubHalCallbacksAndSensorList(); init(); } HalProxy::~HalProxy() { { std::lock_guard<std::mutex> lockGuard(mEventQueueWriteMutex); mPendingWritesRun = false; mThreadsRun.store(false); mWakelockCV.notify_one(); mEventQueueWriteCV.notify_one(); } if (mPendingWritesThread.joinable()) { mPendingWritesThread.join(); } // TODO: Cleanup wakeup thread once it is implemented if (mWakelockThread.joinable()) { mWakelockThread.join(); } } Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) { Loading Loading @@ -140,7 +144,7 @@ Return<Result> HalProxy::initialize( } mPendingWritesThread = std::thread(startPendingWritesThread, this); // TODO: start threads to read wake locks. mWakelockThread = std::thread(startWakelockThread, this); for (size_t i = 0; i < mSubHalList.size(); i++) { auto subHal = mSubHalList[i]; Loading Loading @@ -322,7 +326,7 @@ void HalProxy::initializeSensorList() { } } void HalProxy::initializeSubHalCallbacksAndSensorList() { void HalProxy::init() { initializeSubHalCallbacks(); initializeSensorList(); } Loading @@ -334,11 +338,12 @@ void HalProxy::startPendingWritesThread(HalProxy* halProxy) { void HalProxy::handlePendingWrites() { // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one. std::unique_lock<std::mutex> lock(mEventQueueWriteMutex); while (mPendingWritesRun) { while (mThreadsRun.load()) { mEventQueueWriteCV.wait( lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; }); if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) { std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front(); 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(); Loading @@ -348,10 +353,16 @@ void HalProxy::handlePendingWrites() { pendingWriteEvents.data(), numToWrite, static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ), static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS), kWakelockTimeoutNs, mEventQueueFlag)) { kPendingWriteTimeoutNs, mEventQueueFlag)) { ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite); if (numWakeupEvents > 0) { if (pendingWriteEvents.size() > eventQueueSize) { decrementRefCountAndMaybeReleaseWakelock( countNumWakeupEvents(pendingWriteEvents, eventQueueSize)); } else { mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS)); decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents); } } } lock.lock(); if (pendingWriteEvents.size() > eventQueueSize) { Loading @@ -366,9 +377,60 @@ void HalProxy::handlePendingWrites() { } } void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) { 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) { Loading @@ -384,28 +446,37 @@ void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) { if (numToWrite < events.size()) { // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework // stalls mPendingWriteEventsQueue.push( std::vector<Event>(events.begin() + numToWrite, events.end())); std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end()); mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents}); mEventQueueWriteCV.notify_one(); } } // TODO: Implement the wakelock timeout in these next two methods. Also pass in the subhal // index for better tracking. void HalProxy::incrementRefCountAndMaybeAcquireWakelock() { std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex); 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); acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName); mWakelockCV.notify_one(); } mWakelockRefCount++; mWakelockTimeoutStartTime = getTimeNow(); mWakelockRefCount += delta; if (timeoutStart != nullptr) { *timeoutStart = mWakelockTimeoutStartTime; } return true; } void HalProxy::decrementRefCountAndMaybeReleaseWakelock() { std::lock_guard<std::mutex> lockGuard(mWakelockRefCountMutex); mWakelockRefCount--; 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); release_wake_lock(kWakelockName); } } Loading @@ -427,6 +498,17 @@ ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) { return mSubHalList[static_cast<size_t>(sensorHandle >> 24)]; } 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; } uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) { return sensorHandle & (~kSensorHandleSubHalIndexMask); } Loading @@ -436,7 +518,7 @@ bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) { } void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) { (void)wakelock; if (events.empty() || !mHalProxy->areThreadsRunning()) return; size_t numWakeupEvents; std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents); if (numWakeupEvents > 0) { Loading @@ -450,8 +532,7 @@ void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelo " w/ index %zu.", mSubHalIndex); } mHalProxy->postEventsToMessageQueue(processedEvents); mHalProxy->postEventsToMessageQueue(events, numWakeupEvents, std::move(wakelock)); } ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { Loading @@ -461,13 +542,13 @@ ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) { std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events, size_t* numWakeupEvents) const { std::vector<Event> eventsOut; *numWakeupEvents = 0; std::vector<Event> eventsOut; for (Event event : events) { event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex); eventsOut.push_back(event); if ((mHalProxy->getSensorInfo(event.sensorHandle).flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle); if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) { (*numWakeupEvents)++; } } Loading
sensors/2.0/multihal/ScopedWakelock.cpp +8 −4 Original line number Diff line number Diff line Loading @@ -22,18 +22,22 @@ 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) { // TODO: Move this implementation into HalProxy object instead if (mLocked) { mRefCounter->incrementRefCountAndMaybeAcquireWakelock(); mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs); } } ScopedWakelock::~ScopedWakelock() { // TODO: Move this implementation into HalProxy object instead if (mLocked) { mRefCounter->decrementRefCountAndMaybeReleaseWakelock(); mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs); } } Loading
sensors/2.0/multihal/include/HalProxy.h +86 −38 Original line number Diff line number Diff line Loading @@ -16,9 +16,11 @@ #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> Loading @@ -30,6 +32,7 @@ #include <mutex> #include <queue> #include <thread> #include <utility> namespace android { namespace hardware { Loading Loading @@ -100,45 +103,41 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex); // Below methods follow IScopedWakelockRefCounter /** * Increment ref count and maybe acquire wakelock. */ void incrementRefCountAndMaybeAcquireWakelock() override; /** * Decrement ref count and maybe release wakelock. */ void decrementRefCountAndMaybeReleaseWakelock() override; // 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 5 second timeout. * 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); void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents, ScopedWakelock wakelock); /** * Get the SensorInfo object associated with the sensorHandle. * Get the sensor info associated with that sensorHandle. * * @param sensorHandle The sensorHandle for the sensor. * @param sensorHandle The sensor handle. * * @return The sensor info for the sensor. * @return The sensor info object in the mapping. */ const SensorInfo& getSensorInfo(uint32_t sensorHandle) const { return mSensors.at(sensorHandle); } const SensorInfo& getSensorInfo(uint32_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>; const char* kWakeLockName = "SensorsHAL_WAKEUP"; /** * The Event FMQ where sensor events are written */ Loading Loading @@ -185,23 +184,17 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The single subHal that supports directChannel reporting. ISensorsSubHal* mDirectChannelSubHal = nullptr; //! The mutex for the event queue. std::mutex mEventQueueMutex; //! The timeout for each pending write on background thread for events. static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */; //! The scoped wakelock ref count. size_t mWakelockRefCount = 0; //! The mutex guarding the mWakelockRefCount variable std::mutex mWakelockRefCountMutex; 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 uint32_t kSensorHandleSubHalIndexMask = 0xFF000000; //! The events that were not able to be written to fmq right away std::queue<std::vector<Event>> mPendingWriteEventsQueue; /** * 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; Loading @@ -212,12 +205,32 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! The thread object ptr that handles pending writes std::thread mPendingWritesThread; //! The bool indicating whether to end the pending writes background thread or not bool mPendingWritesRun = true; //! 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 = "SensorsMultiHal"; /** * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries * listed in a config file. Loading @@ -236,9 +249,9 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { void initializeSensorList(); /** * Calls the above two helper methods which are shared in both ctors. * Calls the helper methods that all ctors use. */ void initializeSubHalCallbacksAndSensorList(); void init(); /** * Starts the thread that handles pending writes to event fmq. Loading @@ -250,6 +263,31 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { //! 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 Loading @@ -269,6 +307,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter { */ ISensorsSubHal* getSubHalForSensorHandle(uint32_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. * Loading
sensors/2.0/multihal/include/ScopedWakelock.h +31 −4 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ #pragma once #include <mutex> #include <android/hardware/sensors/2.0/types.h> namespace android { namespace hardware { Loading @@ -24,10 +24,36 @@ namespace sensors { namespace V2_0 { namespace implementation { class IScopedWakelockRefCounter { 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: virtual void incrementRefCountAndMaybeAcquireWakelock() = 0; virtual void decrementRefCountAndMaybeReleaseWakelock() = 0; /** * 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(){}; }; Loading Loading @@ -64,6 +90,7 @@ class ScopedWakelock { private: friend class HalProxyCallback; IScopedWakelockRefCounter* mRefCounter; int64_t mCreatedAtTimeNs; bool mLocked; ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked); ScopedWakelock(const ScopedWakelock&) = delete; Loading