Acquire and Release Wake Lock

Acquire a wake lock in the Sensors 2.0 Default implementation whenever
there are outstanding WAKE_UP events. Release the wake lock whenever
the number of oustanding WAKE_UP events is zero or at least
SensorTimeout::WAKE_LOCK_SECONDS seconds have elapsed since the
previous WAKE_UP event was written to the Event FMQ.

Bug: 111070257
Test: Builds, wake lock is acquired and released as expected.
Change-Id: I7c57724430144fd4022646d1fef1b1fa8bc4235d
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
index 11612d3..db0b148 100644
--- a/sensors/2.0/default/Android.bp
+++ b/sensors/2.0/default/Android.bp
@@ -32,6 +32,7 @@
         "libhidlbase",
         "libhidltransport",
         "liblog",
+        "libpower",
         "libutils",
     ],
 }
diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp
index 17337e2..168b402 100644
--- a/sensors/2.0/default/Sensor.cpp
+++ b/sensors/2.0/default/Sensor.cpp
@@ -86,7 +86,7 @@
     ev.sensorType = SensorType::ADDITIONAL_INFO;
     ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
     std::vector<Event> evs{ev};
-    mCallback->postEvents(evs);
+    mCallback->postEvents(evs, isWakeUpSensor());
 
     return Result::OK;
 }
@@ -113,7 +113,7 @@
             if (now >= nextSampleTime) {
                 mLastSampleTimeNs = now;
                 nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
-                mCallback->postEvents(readEvents());
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
             }
 
             mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
@@ -121,6 +121,10 @@
     }
 }
 
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
 std::vector<Event> Sensor::readEvents() {
     std::vector<Event> events;
     Event event;
@@ -155,7 +159,7 @@
     } else if (!supportsDataInjection()) {
         result = Result::INVALID_OPERATION;
     } else if (mMode == OperationMode::DATA_INJECTION) {
-        mCallback->postEvents(std::vector<Event>{event});
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
     } else {
         result = Result::BAD_VALUE;
     }
diff --git a/sensors/2.0/default/Sensor.h b/sensors/2.0/default/Sensor.h
index 7fb927a..3ab2299 100644
--- a/sensors/2.0/default/Sensor.h
+++ b/sensors/2.0/default/Sensor.h
@@ -40,7 +40,7 @@
 class ISensorsEventCallback {
    public:
     virtual ~ISensorsEventCallback(){};
-    virtual void postEvents(const std::vector<Event>& events) = 0;
+    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
 };
 
 class Sensor {
@@ -62,6 +62,8 @@
     virtual std::vector<Event> readEvents();
     static void startThread(Sensor* sensor);
 
+    bool isWakeUpSensor();
+
     bool mIsEnabled;
     int64_t mSamplingPeriodNs;
     int64_t mLastSampleTimeNs;
diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp
index 4346ee1..18240da 100644
--- a/sensors/2.0/default/Sensors.cpp
+++ b/sensors/2.0/default/Sensors.cpp
@@ -30,8 +30,16 @@
 using ::android::hardware::sensors::V1_0::RateLevel;
 using ::android::hardware::sensors::V1_0::Result;
 using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
 
-Sensors::Sensors() : mEventQueueFlag(nullptr) {
+constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+Sensors::Sensors()
+    : mEventQueueFlag(nullptr),
+      mOutstandingWakeUpEvents(0),
+      mReadWakeLockQueueRun(false),
+      mAutoReleaseWakeLockTime(0),
+      mHasWakeLock(false) {
     std::shared_ptr<AccelSensor> accel =
         std::make_shared<AccelSensor>(1 /* sensorHandle */, this /* callback */);
     mSensors[accel->getSensorInfo().sensorHandle] = accel;
@@ -39,6 +47,8 @@
 
 Sensors::~Sensors() {
     deleteEventFlag();
+    mReadWakeLockQueueRun = false;
+    mWakeLockThread.join();
 }
 
 // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
@@ -101,6 +111,10 @@
         result = Result::BAD_VALUE;
     }
 
+    // Start the thread to read events from the Wake Lock FMQ
+    mReadWakeLockQueueRun = true;
+    mWakeLockThread = std::thread(startReadWakeLockThread, this);
+
     return result;
 }
 
@@ -147,15 +161,67 @@
     return Return<void>();
 }
 
-void Sensors::postEvents(const std::vector<Event>& events) {
-    std::lock_guard<std::mutex> l(mLock);
+void Sensors::postEvents(const std::vector<Event>& events, bool wakeup) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    if (mEventQueue->write(events.data(), events.size())) {
+        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
 
-    // TODO: read events from the Wake Lock FMQ in the right place
-    std::vector<uint32_t> tmp(mWakeLockQueue->availableToRead());
-    mWakeLockQueue->read(tmp.data(), mWakeLockQueue->availableToRead());
+        if (wakeup) {
+            // Keep track of the number of outstanding WAKE_UP events in order to properly hold
+            // a wake lock until the framework has secured a wake lock
+            updateWakeLock(events.size(), 0 /* eventsHandled */);
+        }
+    }
+}
 
-    mEventQueue->write(events.data(), events.size());
-    mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+void Sensors::updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
+    std::lock_guard<std::mutex> lock(mWakeLockLock);
+    int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
+    if (newVal < 0) {
+        mOutstandingWakeUpEvents = 0;
+    } else {
+        mOutstandingWakeUpEvents = newVal;
+    }
+
+    if (eventsWritten > 0) {
+        // Update the time at which the last WAKE_UP event was sent
+        mAutoReleaseWakeLockTime = ::android::uptimeMillis() +
+                                   static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000;
+    }
+
+    if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
+        mHasWakeLock = true;
+    } else if (mHasWakeLock) {
+        // Check if the wake lock should be released automatically if
+        // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written to
+        // the Wake Lock FMQ.
+        if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
+            ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
+                  SensorTimeout::WAKE_LOCK_SECONDS);
+            mOutstandingWakeUpEvents = 0;
+        }
+
+        if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
+            mHasWakeLock = false;
+        }
+    }
+}
+
+void Sensors::readWakeLockFMQ() {
+    while (mReadWakeLockQueueRun.load()) {
+        constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
+        uint32_t eventsHandled = 0;
+
+        // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to ensure
+        // that any held wake lock is able to be released if it is held for too long.
+        mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, kReadTimeoutNs);
+        updateWakeLock(0 /* eventsWritten */, eventsHandled);
+    }
+}
+
+void Sensors::startReadWakeLockThread(Sensors* sensors) {
+    sensors->readWakeLockFMQ();
 }
 
 void Sensors::deleteEventFlag() {
diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h
index f543935..eba3f97 100644
--- a/sensors/2.0/default/Sensors.h
+++ b/sensors/2.0/default/Sensors.h
@@ -21,10 +21,13 @@
 
 #include <android/hardware/sensors/2.0/ISensors.h>
 #include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include <atomic>
 #include <memory>
+#include <thread>
 
 namespace android {
 namespace hardware {
@@ -80,7 +83,7 @@
     Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
                                     configDirectReport_cb _hidl_cb) override;
 
-    void postEvents(const std::vector<Event>& events) override;
+    void postEvents(const std::vector<Event>& events, bool wakeup) override;
 
    private:
     /**
@@ -88,6 +91,18 @@
      */
     void deleteEventFlag();
 
+    /**
+     * Function to read the Wake Lock FMQ and release the wake lock when appropriate
+     */
+    void readWakeLockFMQ();
+
+    static void startReadWakeLockThread(Sensors* sensors);
+
+    /**
+     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
+     */
+    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled);
+
     using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
     using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
 
@@ -117,9 +132,39 @@
     std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
 
     /**
-     * Lock to protect writes and reads to the FMQs
+     * Lock to protect writes to the FMQs
      */
-    std::mutex mLock;
+    std::mutex mWriteLock;
+
+    /**
+     * Lock to protect acquiring and releasing the wake lock
+     */
+    std::mutex mWakeLockLock;
+
+    /**
+     * Track the number of WAKE_UP events that have not been handled by the framework
+     */
+    uint32_t mOutstandingWakeUpEvents;
+
+    /**
+     * A thread to read the Wake Lock FMQ
+     */
+    std::thread mWakeLockThread;
+
+    /**
+     * Flag to indicate that the Wake Lock Thread should continue to run
+     */
+    std::atomic_bool mReadWakeLockQueueRun;
+
+    /**
+     * Track the time when the wake lock should automatically be released
+     */
+    int64_t mAutoReleaseWakeLockTime;
+
+    /**
+     * Flag to indicate if a wake lock has been acquired
+     */
+    bool mHasWakeLock;
 };
 
 }  // namespace implementation