MH2 | Implement dynamic sensors callbacks on HalProxy

Additionally, have HalProxyCallback::processEvents use
HalProxy::setSubHalIndex static method instead of its own helper.
Add unit tests to test the dynamic sensor methods.

Bug: 136511617
Test: New unit tests are passing.
Change-Id: Ib903291a83df2fafa480082f9305c594bd325f79
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 1fbc787..5aa3b3d 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -38,6 +38,18 @@
 
 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 Return<void>();
 }
 
-Return<void> HalProxy::onDynamicSensorsConnected(
-        const hidl_vec<SensorInfo>& /* dynamicSensorsAdded */, int32_t /* subHalIndex */) {
-    // TODO: Map the SensorInfo to the global list and then invoke the framework's callback.
+Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                                 int32_t subHalIndex) {
+    std::vector<SensorInfo> sensors;
+    {
+        std::lock_guard<std::mutex> 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<void>();
 }
 
 Return<void> HalProxy::onDynamicSensorsDisconnected(
-        const hidl_vec<int32_t>& /* dynamicSensorHandlesRemoved */, int32_t /* subHalIndex */) {
-    // TODO: Unmap the SensorInfo from the global list and then invoke the framework's callback.
+        const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
+    // TODO: Block this call until all pending events are flushed from queue
+    std::vector<int32_t> sensorHandles;
+    {
+        std::lock_guard<std::mutex> 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<void>();
 }
 
@@ -264,7 +306,7 @@
         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 @@
     return sensorHandle & (~kSensorHandleSubHalIndexMask);
 }
 
+bool HalProxy::subHalIndexIsClear(uint32_t sensorHandle) {
+    return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
+}
+
 void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
     (void)wakelock;
     size_t numWakeupEvents;
@@ -418,7 +464,7 @@
     std::vector<Event> 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 @@
     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 ae4b2c5..47571a6 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -176,6 +176,9 @@
      */
     std::map<uint32_t, SensorInfo> mSensors;
 
+    //! Map of the dynamic sensors that have been added to halproxy.
+    std::map<uint32_t, SensorInfo> mDynamicSensors;
+
     //! The current operation mode for all subhals.
     OperationMode mCurrentOperationMode = OperationMode::NORMAL;
 
@@ -212,6 +215,9 @@
     //! 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 @@
      * @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 @@
 
     std::vector<Event> processEvents(const std::vector<Event>& 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 61fb14c..c8fbb73 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 <chrono>
+#include <set>
 #include <thread>
 #include <vector>
 
@@ -38,6 +39,7 @@
 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 @@
     }
 };
 
+// The sensors callback that expects a variable list of sensors to be added
+class TestSensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
+                                 dynamicSensorsAdded.end());
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
+                                          dynamicSensorHandlesRemoved.begin(),
+                                          dynamicSensorHandlesRemoved.end());
+        return Return<void>();
+    }
+
+    const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
+    const std::vector<int32_t>& getSensorHandlesDisconnected() const {
+        return mSensorHandlesDisconnected;
+    }
+
+  private:
+    std::vector<SensorInfo> mSensorsConnected;
+    std::vector<int32_t> mSensorHandlesDisconnected;
+};
+
 // Helper declarations follow
 
 /**
@@ -129,6 +159,20 @@
  */
 std::vector<Event> 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<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles);
+
 // Tests follow
 TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
     AllSensorsSubHal subHal;
@@ -396,6 +440,83 @@
     // 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<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = std::make_unique<EventMessageQueue>(0, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
+            std::make_unique<WakeupMessageQueue>(0, true);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+
+    std::vector<SensorInfo> 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<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = std::make_unique<EventMessageQueue>(0, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
+            std::make_unique<WakeupMessageQueue>(0, true);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
+                                                 nonDynamicSensorHandles.end());
+
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          sensorHandlesToExpect.begin(),
+                                          sensorHandlesToExpect.end());
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          nonDynamicSensorHandles.begin(),
+                                          nonDynamicSensorHandles.end());
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> 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<SensorInfo>& proxySensorsList,
                                        const std::vector<SensorInfo>& subHalSensorsList) {
@@ -463,4 +584,18 @@
     return events;
 }
 
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles) {
+    for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(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 d581c49..cf3ae75 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 Void();
 }
 
+void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
+        const std::vector<SensorInfo>& sensorsAdded) {
+    mCallback->onDynamicSensorsConnected(sensorsAdded);
+}
+
+void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
+        const std::vector<int32_t>& 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 61caa2c..c1e3647 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 @@
      */
     std::map<int32_t, std::shared_ptr<Sensor>> 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 @@
      */
     sp<IHalProxyCallback> 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 @@
     Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
 };
 
+class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
+  public:
+    void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
+    void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
+};
+
 }  // namespace implementation
 }  // namespace subhal
 }  // namespace V2_0