Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75cc7bf2 authored by Stan Rokita's avatar Stan Rokita
Browse files

MH2 | Implement wakelock processing thread

Bug: 136511617
Test: Unit tests cannot be written for this change. Integration testing
will be performed later.

Change-Id: I651b5fde77c6017b3270413de896a947d95ff5f8
parent 5bd809c5
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ cc_defaults {
        "libpower",
        "libutils",
    ],
    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}

cc_binary {
@@ -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 {
@@ -66,4 +66,7 @@ cc_test_library {
    export_header_lib_headers: [
        "android.hardware.sensors@2.0-multihal.header",
    ],
    shared_libs: [
        "libutils",
    ],
}
+118 −37
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include <dlfcn.h>

#include <cinttypes>
#include <fstream>
#include <functional>
#include <thread>
@@ -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*);

@@ -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) {
@@ -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];
@@ -322,7 +326,7 @@ void HalProxy::initializeSensorList() {
    }
}

void HalProxy::initializeSubHalCallbacksAndSensorList() {
void HalProxy::init() {
    initializeSubHalCallbacks();
    initializeSensorList();
}
@@ -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();
@@ -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) {
@@ -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) {
@@ -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);
    }
}

@@ -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);
}
@@ -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) {
@@ -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) {
@@ -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)++;
        }
    }
+8 −4
Original line number Diff line number Diff line
@@ -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);
    }
}

+86 −38
Original line number Diff line number Diff line
@@ -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>
@@ -30,6 +32,7 @@
#include <mutex>
#include <queue>
#include <thread>
#include <utility>

namespace android {
namespace hardware {
@@ -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
     */
@@ -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;
@@ -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.
@@ -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.
@@ -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
@@ -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.
     *
+31 −4
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

#pragma once

#include <mutex>
#include <android/hardware/sensors/2.0/types.h>

namespace android {
namespace hardware {
@@ -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(){};
};
@@ -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