dynamic_sensor: Support timing out sensor operations. am: 9b8bc0f7c1 am: fb93d2f677

Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/libhardware/+/17542700

Change-Id: I0f7fba86f3b6647ab1a9e8d1b8592190ab584488
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp b/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp
index be1a004..efac5e9 100644
--- a/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp
+++ b/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp
@@ -87,7 +87,7 @@
     }
 
     return operateSensor(handle,
-            [&enable] (sp<BaseSensorObject> s)->int {
+            [=] (sp<BaseSensorObject> s)->int {
                 return s->enable(enable);
             });
 }
@@ -98,7 +98,7 @@
         return 0;
     }
     return operateSensor(handle,
-            [&sample_period, &batch_period] (sp<BaseSensorObject> s)->int {
+            [=] (sp<BaseSensorObject> s)->int {
                 return s->batch(sample_period, batch_period);
             });
 }
@@ -239,6 +239,87 @@
     return mMetaSensor;
 }
 
+int DynamicSensorManager::operateSensor(
+        int handle, OperateSensorFunc sensorFunc) {
+    std::shared_future<int> sensorOp;
+    {
+        std::lock_guard<std::mutex> lock(mSensorOpQueueLock);
+
+        // Invoke the function asynchronously.
+        sensorOp = std::async(
+                [this, handle = handle, sensorFunc = sensorFunc,
+                 sensorOpIndex = mNextSensorOpIndex] ()->int {
+            return operateSensor(handle, sensorFunc, sensorOpIndex);
+        }).share();
+
+        // Add sensor operation to the queue.
+        mSensorOpQueue.push({mNextSensorOpIndex, sensorOp});
+        mNextSensorOpIndex++;
+    }
+
+    // Wait for the sensor operation to complete.
+    if (sensorOp.wait_for(kSensorOpTimeout) != std::future_status::ready) {
+        ALOGE("sensor operation timed out");
+        return TIMED_OUT;
+    }
+
+    return sensorOp.get();
+}
+
+int DynamicSensorManager::operateSensor(
+        int handle, OperateSensorFunc sensorFunc, uint64_t sensorOpIndex) {
+    int rv = 0;
+
+    // Wait until this sensor operation is at the head of the queue.
+    while (1) {
+        std::shared_future<int> headSensorOp;
+
+        {
+            std::lock_guard<std::mutex> lock(mSensorOpQueueLock);
+
+            if (mSensorOpQueue.front().first == sensorOpIndex) {
+                break;
+            }
+            headSensorOp = mSensorOpQueue.front().second;
+        }
+        headSensorOp.wait();
+    }
+
+    // Perform sensor operation.
+    sp<BaseSensorObject> sensor;
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        const auto i = mMap.find(handle);
+        if (i == mMap.end()) {
+            rv = BAD_VALUE;
+        }
+        if (rv == 0) {
+            sensor = i->second.promote();
+            if (sensor == nullptr) {
+                // sensor object is already gone
+                rv = BAD_VALUE;
+            }
+        }
+    }
+    if (rv == 0) {
+        rv = sensorFunc(sensor);
+    }
+
+    // Remove sensor operation from queue. When the operation's shared state is
+    // destroyed, execution of this function ceases. Thus, if the state is
+    // destroyed when the operation is removed from the queue, the lock will
+    // never be released. To prevent that, the state is shared locally, so it
+    // isn't destroyed until this function completes.
+    std::shared_future<int> sensorOp;
+    {
+        std::lock_guard<std::mutex> lock(mSensorOpQueueLock);
+        sensorOp = mSensorOpQueue.front().second;
+        mSensorOpQueue.pop();
+    }
+
+    return rv;
+}
+
 DynamicSensorManager::ConnectionReport::ConnectionReport(
         int handle, sp<BaseSensorObject> sensor) :
         mSensor(*(sensor->getSensor())),
diff --git a/modules/sensors/dynamic_sensor/DynamicSensorManager.h b/modules/sensors/dynamic_sensor/DynamicSensorManager.h
index 264582e..b8a7320 100644
--- a/modules/sensors/dynamic_sensor/DynamicSensorManager.h
+++ b/modules/sensors/dynamic_sensor/DynamicSensorManager.h
@@ -22,7 +22,9 @@
 #include <hardware/sensors.h>
 #include <utils/RefBase.h>
 
+#include <future>
 #include <mutex>
+#include <queue>
 #include <string>
 #include <unordered_map>
 #include <vector>
@@ -92,24 +94,13 @@
     // returns next available handle to use upon a new sensor connection, or -1 if we run out.
     int getNextAvailableHandle();
 
-    // TF:  int foo(sp<BaseSensorObject> obj);
-    template <typename TF>
-    int operateSensor(int handle, TF f) const {
-        sp<BaseSensorObject> s;
-        {
-            std::lock_guard<std::mutex> lk(mLock);
-            const auto i = mMap.find(handle);
-            if (i == mMap.end()) {
-                return BAD_VALUE;
-            }
-            s = i->second.promote();
-            if (s == nullptr) {
-                // sensor object is already gone
-                return BAD_VALUE;
-            }
-        }
-        return f(s);
-    }
+    // Runs a sensor function with a timeout. On timeout, function could still
+    // be running, so any function parameter or closure lifetimes should match
+    // the function's lifetime.
+    using OperateSensorFunc = std::function<int(sp<BaseSensorObject>)>;
+    int operateSensor(int handle, OperateSensorFunc sensorFunc);
+    int operateSensor(int handle, OperateSensorFunc sensorFunc,
+                      uint64_t sensorOpIndex);
 
     // available sensor handle space
     const std::pair<int, int> mHandleRange;
@@ -133,6 +124,14 @@
 
     // daemons
     std::vector<sp<BaseDynamicSensorDaemon>> mDaemonVector;
+
+    // Sensor operation queue. Calls to the sensor HAL must complete within 1
+    // second.
+    static constexpr std::chrono::milliseconds
+            kSensorOpTimeout = std::chrono::milliseconds(900);
+    std::mutex mSensorOpQueueLock;
+    std::queue<std::pair<uint64_t, std::shared_future<int>>> mSensorOpQueue;
+    uint64_t mNextSensorOpIndex = 0;
 };
 
 } // namespace SensorHalExt