MultiHal 2.0 - Get sensors list from subhals

Implement SubHal constructors. The default ctor will get the SubHal
object pointers from dynamic libraries. The test ctor will take a vector
of SubHal objects. Implment the HalProxy getSensorsList method which
will return all the sensors from the subhal objects. Create one unit
test for getSensorsList as well.

Bug: 136511617
Test: Flashed onto device and observed proper logs for both test
subhals. Also, passed getSensorsList test.

Change-Id: I6e8ca4883c50daabbd7b0955d3664f66b6cd74bf
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index dcdccac..d8bde83 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -70,42 +70,12 @@
 
 HalProxy::HalProxy() {
     const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf";
-    std::ifstream subHalConfigStream(kMultiHalConfigFilePath);
-    if (!subHalConfigStream) {
-        LOG_FATAL("Failed to load subHal config file: %s", kMultiHalConfigFilePath);
-    } else {
-        std::string subHalLibraryFile;
-        while (subHalConfigStream >> subHalLibraryFile) {
-            void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
-            if (handle == nullptr) {
-                LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str());
-            } else {
-                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
-                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
-                if (sensorsHalGetSubHalPtr == nullptr) {
-                    LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s",
-                              subHalLibraryFile.c_str());
-                } else {
-                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
-                            *sensorsHalGetSubHalPtr;
-                    uint32_t version;
-                    ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
-                    if (version != SUB_HAL_2_0_VERSION) {
-                        LOG_FATAL("SubHal version was not 2.0 for library: %s",
-                                  subHalLibraryFile.c_str());
-                    } else {
-                        ALOGI("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
-                        mSubHalList.push_back(subHal);
-                    }
-                }
-            }
-        }
-    }
-    // TODO: Discover sensors
+    initializeSubHalListFromConfigFile(kMultiHalConfigFilePath);
+    initializeSensorList();
 }
 
 HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
-    // TODO: Perform the same steps as the empty constructor.
+    initializeSensorList();
 }
 
 HalProxy::~HalProxy() {
@@ -113,8 +83,8 @@
     // state.
 }
 
-Return<void> HalProxy::getSensorsList(getSensorsList_cb /* _hidl_cb */) {
-    // TODO: Output sensors list created as part of HalProxy().
+Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
+    _hidl_cb(mSensorList);
     return Void();
 }
 
@@ -217,6 +187,60 @@
     return Return<void>();
 }
 
+void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
+    std::ifstream subHalConfigStream(configFileName);
+    if (!subHalConfigStream) {
+        LOG_FATAL("Failed to load subHal config file: %s", configFileName);
+    } else {
+        std::string subHalLibraryFile;
+        while (subHalConfigStream >> subHalLibraryFile) {
+            void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
+            if (handle == nullptr) {
+                LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str());
+            } else {
+                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
+                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
+                if (sensorsHalGetSubHalPtr == nullptr) {
+                    LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s",
+                              subHalLibraryFile.c_str());
+                } else {
+                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
+                            *sensorsHalGetSubHalPtr;
+                    uint32_t version;
+                    ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
+                    if (version != SUB_HAL_2_0_VERSION) {
+                        LOG_FATAL("SubHal version was not 2.0 for library: %s",
+                                  subHalLibraryFile.c_str());
+                    } else {
+                        ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+                        mSubHalList.push_back(subHal);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void HalProxy::initializeSensorList() {
+    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+        auto result = subHal->getSensorsList([&](const auto& list) {
+            for (SensorInfo sensor : list) {
+                if ((sensor.sensorHandle & 0xFF000000) != 0) {
+                    ALOGE("SubHal sensorHandle's first byte was not 0");
+                } else {
+                    ALOGV("Loaded sensor: %s", sensor.name.c_str());
+                    sensor.sensorHandle |= (subHalIndex << 24);
+                    mSensorList.push_back(sensor);
+                }
+            }
+        });
+        if (!result.isOk()) {
+            ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
+        }
+    }
+}
+
 ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) {
     return mSubHalList[static_cast<size_t>(sensorHandle >> 24)];
 }
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index 809d07e..b0261c8 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -39,7 +39,8 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 
-struct HalProxy : public ISensors {
+class HalProxy : public ISensors {
+  public:
     using Event = ::android::hardware::sensors::V1_0::Event;
     using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
     using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
@@ -119,6 +120,27 @@
      */
     std::vector<ISensorsSubHal*> mSubHalList;
 
+    /**
+     * List of SensorInfo objects that contains the sensor info from subhals as
+     * well as the modified sensor handle for the framework.
+     *
+     * The subhal index is encoded in the first byte of the sensor handle and
+     * the remaining bytes are generated by the subhal.
+     */
+    std::vector<SensorInfo> mSensorList;
+
+    /**
+     * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
+     * listed in a config file.
+     */
+    void initializeSubHalListFromConfigFile(const char* configFileName);
+
+    /**
+     * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
+     * subhal.
+     */
+    void initializeSensorList();
+
     /*
      * Get the subhal pointer which can be found by indexing into the mSubHalList vector
      * using the index from the first byte of sensorHandle.
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
index 75e93a1..e84cba5 100644
--- a/sensors/2.0/multihal/include/SubHal.h
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -137,6 +137,7 @@
  * sub-HALs can continue to use the lower 3 bytes of the handle.
  */
 class ISensorsSubHal : public ISensors {
+  public:
     // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
     // the version below to allow communciation logic to centralized in the HalProxy
     Return<Result> initialize(
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
index 13d80f7..21ceb0c 100644
--- a/sensors/2.0/multihal/tests/Android.bp
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -86,4 +86,4 @@
         "libutils",
     ],
     test_suites: ["device-tests"],
-}
\ No newline at end of file
+}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
index 9edc88a..28004d0 100644
--- a/sensors/2.0/multihal/tests/HalProxy_test.cpp
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -18,7 +18,14 @@
 #include "HalProxy.h"
 #include "SensorsSubHal.h"
 
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
 using ::android::hardware::sensors::V2_0::implementation::HalProxy;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
 using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
 
 // TODO: Add more interesting tests such as
@@ -30,10 +37,55 @@
 //
 // See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info
 // on how tests are set up and for information on the gtest framework itself.
-TEST(HalProxyTest, ExampleTest) {
-    SensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> fakeSubHals;
-    fakeSubHals.push_back(&subHal);
 
+// Helper declarations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList);
+
+// Tests follow
+TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
     HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& proxySensorsList) {
+        subHal.getSensorsList([&](const auto& subHalSensorsList) {
+            testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
+        });
+    });
+}
+
+TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
+    ContinuousSensorsSubHal continuousSubHal;
+    OnChangeSensorsSubHal onChangeSubHal;
+    std::vector<ISensorsSubHal*> fakeSubHals;
+    fakeSubHals.push_back(&continuousSubHal);
+    fakeSubHals.push_back(&onChangeSubHal);
+    HalProxy proxy(fakeSubHals);
+
+    std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
+
+    proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
+    continuousSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+    onChangeSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+
+    testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
+}
+
+// Helper implementations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList) {
+    EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
+
+    for (size_t i = 0; i < proxySensorsList.size(); i++) {
+        const SensorInfo& proxySensor = proxySensorsList[i];
+        const SensorInfo& subHalSensor = subHalSensorsList[i];
+
+        EXPECT_EQ(proxySensor.type, subHalSensor.type);
+        EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
+    }
 }
\ No newline at end of file
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
index 8d45982..fe47161 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -20,7 +20,16 @@
 #include <log/log.h>
 
 ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
+            subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
+#else
     static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
+#endif  // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
     *version = SUB_HAL_2_0_VERSION;
     return &subHal;
 }
@@ -42,22 +51,7 @@
 using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
 using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
 
-SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {
-#ifdef SUPPORT_CONTINUOUS_SENSORS
-    AddSensor<AccelSensor>();
-    AddSensor<GyroSensor>();
-    AddSensor<MagnetometerSensor>();
-    AddSensor<PressureSensor>();
-#endif  // SUPPORT_CONTINUOUS_SENSORS
-
-#ifdef SUPPORT_ON_CHANGE_SENSORS
-    AddSensor<AmbientTempSensor>();
-    AddSensor<DeviceTempSensor>();
-    AddSensor<LightSensor>();
-    AddSensor<ProximitySensor>();
-    AddSensor<RelativeHumiditySensor>();
-#endif  // SUPPORT_ON_CHANGE_SENSORS
-}
+SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
 
 // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
 Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
@@ -171,6 +165,33 @@
     mCallback->postEvents(events, std::move(wakelock));
 }
 
+ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
+    AddSensor<AccelSensor>();
+    AddSensor<GyroSensor>();
+    AddSensor<MagnetometerSensor>();
+    AddSensor<PressureSensor>();
+}
+
+OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
+    AddSensor<AmbientTempSensor>();
+    AddSensor<DeviceTempSensor>();
+    AddSensor<LightSensor>();
+    AddSensor<ProximitySensor>();
+    AddSensor<RelativeHumiditySensor>();
+}
+
+AllSensorsSubHal::AllSensorsSubHal() {
+    AddSensor<AccelSensor>();
+    AddSensor<GyroSensor>();
+    AddSensor<MagnetometerSensor>();
+    AddSensor<PressureSensor>();
+    AddSensor<AmbientTempSensor>();
+    AddSensor<DeviceTempSensor>();
+    AddSensor<LightSensor>();
+    AddSensor<ProximitySensor>();
+    AddSensor<RelativeHumiditySensor>();
+}
+
 }  // 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 93009d5..d94d73d 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -20,6 +20,8 @@
 
 #include "Sensor.h"
 
+#include <vector>
+
 namespace android {
 namespace hardware {
 namespace sensors {
@@ -81,7 +83,7 @@
     // Method from ISensorsEventCallback.
     void postEvents(const std::vector<Event>& events, bool wakeup) override;
 
-  private:
+  protected:
     template <class SensorType>
     void AddSensor() {
         std::shared_ptr<SensorType> sensor =
@@ -89,6 +91,7 @@
         mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
     }
 
+  private:
     /**
      * 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
@@ -107,6 +110,24 @@
     int32_t mNextHandle;
 };
 
+// SubHal that has continuous sensors for testing purposes.
+class ContinuousSensorsSubHal : public SensorsSubHal {
+  public:
+    ContinuousSensorsSubHal();
+};
+
+// SubHal that has on-change sensors for testing purposes.
+class OnChangeSensorsSubHal : public SensorsSubHal {
+  public:
+    OnChangeSensorsSubHal();
+};
+
+// SubHal that has both continuous and on-change sensors for testing purposes.
+class AllSensorsSubHal : public SensorsSubHal {
+  public:
+    AllSensorsSubHal();
+};
+
 }  // namespace implementation
 }  // namespace subhal
 }  // namespace V2_0