Merge "Factor the client/server Library Out" into rvc-qpr-dev
diff --git a/hal/sensors/2.0/Android.bp b/hal/sensors/2.0/Android.bp
index 0ed62a1..e30e632 100644
--- a/hal/sensors/2.0/Android.bp
+++ b/hal/sensors/2.0/Android.bp
@@ -53,6 +53,23 @@
 }
 
 cc_test_host {
+    name: "android.hardware.sensors@2.0-Google-IIO-Subhal_test",
+    srcs: [
+        "iio_utils.cpp",
+        "tests/IioUtilsTest.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+}
+
+cc_test_host {
     name: "android.hardware.sensors@2.0-Google-IIO-Subhal_test-MultiPoll",
     srcs: [
         "MultiPoll.cpp",
@@ -68,3 +85,4 @@
         "liblog",
     ],
 }
+
diff --git a/hal/sensors/2.0/Sensor.cpp b/hal/sensors/2.0/Sensor.cpp
index a5338ad..1d2ea80 100644
--- a/hal/sensors/2.0/Sensor.cpp
+++ b/hal/sensors/2.0/Sensor.cpp
@@ -456,10 +456,9 @@
     std::string buffer_path;
     mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
     mSensorInfo.name = data.name;
-    mSensorInfo.resolution = data.resolution;
+    mSensorInfo.resolution = data.resolution * data.scale;
     mSensorInfo.maxRange = data.max_range * data.scale;
-    mSensorInfo.power =
-            (data.power_microwatts / 1000.f) / SENSOR_VOLTAGE_DEFAULT;  // converting uW to mA
+    mSensorInfo.power = 0;
     mIioData = data;
     setOrientation(config);
     status_t ret = setAdditionalInfoFrames(config);
diff --git a/hal/sensors/2.0/SensorsSubHal.cpp b/hal/sensors/2.0/SensorsSubHal.cpp
index 4d80d9f..4a615af 100644
--- a/hal/sensors/2.0/SensorsSubHal.cpp
+++ b/hal/sensors/2.0/SensorsSubHal.cpp
@@ -42,9 +42,6 @@
 using ::sensor::hal::configuration::V1_0::Sensor;
 using ::sensor::hal::configuration::V1_0::SensorHalConfiguration;
 
-#define SENSOR_SUPPORTED(SENSOR_NAME, SENSOR_TYPE) \
-    { .name = SENSOR_NAME, .type = SENSOR_TYPE, }
-
 #define SENSOR_XML_CONFIG_FILE_NAME "sensor_hal_configuration.xml"
 static const char* gSensorConfigLocationList[] = {"/odm/etc/sensors/", "/vendor/etc/sensors/"};
 static const int gSensorConfigLocationListSize =
@@ -52,11 +49,6 @@
 
 #define MODULE_NAME "android.hardware.sensors@2.0-Google-IIO-Subhal"
 
-static const std::vector<sensors_supported_hal> sensors_supported = {
-        SENSOR_SUPPORTED("scmi.iio.accel", SensorType::ACCELEROMETER),
-        SENSOR_SUPPORTED("scmi.iio.gyro", SensorType::GYROSCOPE),
-};
-
 static std::optional<std::vector<Sensor>> readSensorsConfigFromXml() {
     for (int i = 0; i < gSensorConfigLocationListSize; i++) {
         const auto sensor_config_file =
@@ -86,11 +78,31 @@
     return std::nullopt;
 }
 
+static bool isSensorSupported(iio_device_data* sensor) {
+#define SENSOR_SUPPORTED(SENSOR_NAME, SENSOR_TYPE) \
+    { .name = SENSOR_NAME, .type = SENSOR_TYPE, }
+    static const std::vector<sensors_supported_hal> supported_sensors = {
+            SENSOR_SUPPORTED("scmi.iio.accel", SensorType::ACCELEROMETER),
+            SENSOR_SUPPORTED("scmi.iio.gyro", SensorType::GYROSCOPE),
+    };
+#undef SENSOR_SUPPORTED
+
+    if (!sensor) return false;
+
+    auto iter = std::find_if(
+            supported_sensors.begin(), supported_sensors.end(),
+            [&sensor](const auto& candidate) -> bool { return candidate.name == sensor->name; });
+    if (iter == supported_sensors.end()) return false;
+
+    sensor->type = iter->type;
+    return true;
+}
+
 SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {
     int err;
     std::vector<iio_device_data> iio_devices;
     const auto sensors_config_list = readSensorsConfigFromXml();
-    err = load_iio_devices(&iio_devices, sensors_supported);
+    err = load_iio_devices(DEFAULT_IIO_DIR, &iio_devices, isSensorSupported);
     if (err == 0) {
         for (auto& iio_device : iio_devices) {
             err = scan_elements(iio_device.sysfspath, &iio_device);
diff --git a/hal/sensors/2.0/iio_utils.cpp b/hal/sensors/2.0/iio_utils.cpp
index abd5d3c..84360b2 100644
--- a/hal/sensors/2.0/iio_utils.cpp
+++ b/hal/sensors/2.0/iio_utils.cpp
@@ -29,15 +29,13 @@
 #include <memory>
 
 static const char* IIO_DEVICE_BASE = "iio:device";
-static const char* DEVICE_IIO_DIR = "/sys/bus/iio/devices/";
 static const char* IIO_SCAN_ELEMENTS_EN = "_en";
 static const char* IIO_SFA_FILENAME = "sampling_frequency_available";
 static const char* IIO_SCALE_FILENAME = "_scale";
 static const char* IIO_SAMPLING_FREQUENCY = "_sampling_frequency";
 static const char* IIO_BUFFER_ENABLE = "buffer/enable";
-static const char* IIO_POWER_FILENAME = "sensor_power";
-static const char* IIO_MAX_RANGE_FILENAME = "sensor_max_range";
-static const char* IIO_RESOLUTION_FILENAME = "sensor_resolution";
+static const char* IIO_NAME_FILENAME = "name";
+static const char* IIO_RANGE_AVAIL_FILENAME = "raw_available";
 
 namespace android {
 namespace hardware {
@@ -46,6 +44,8 @@
 namespace subhal {
 namespace implementation {
 
+const char* DEFAULT_IIO_DIR = "/sys/bus/iio/devices/";
+
 using DirPtr = std::unique_ptr<DIR, decltype(&closedir)>;
 using FilePtr = std::unique_ptr<FILE, decltype(&fclose)>;
 
@@ -126,18 +126,10 @@
     return sysfs_read_val(file, "%hhu\n", val);
 }
 
-static int sysfs_read_uint(const std::string& file, unsigned int* val) {
-    return sysfs_read_val(file, "%u\n", val);
-}
-
 static int sysfs_read_float(const std::string& file, float* val) {
     return sysfs_read_val(file, "%f\n", val);
 }
 
-static int sysfs_read_int64(const std::string& file, int64_t* val) {
-    return sysfs_read_val(file, "%lld\n", val);
-}
-
 static int sysfs_read_str(const std::string& file, std::string* str) {
     std::ifstream infile(file);
     if (!infile.is_open()) return -EINVAL;
@@ -170,30 +162,64 @@
     int ret = 0;
     char* rest;
     std::string line;
+    DirPtr dp(nullptr, closedir);
+    const struct dirent* ent;
 
-    const std::string filename = device_dir + "/" + IIO_SFA_FILENAME;
-
-    ret = sysfs_read_str(filename, &line);
-    if (ret < 0) return ret;
-    char* pch = strtok_r(const_cast<char*>(line.c_str()), " ,", &rest);
-    while (pch != nullptr) {
-        sfa->push_back(atof(pch));
-        pch = strtok_r(nullptr, " ,", &rest);
+    ret = sysfs_opendir(device_dir, &dp);
+    if (ret) return ret;
+    while (ent = readdir(dp.get()), ent != nullptr) {
+        if (str_has_suffix(ent->d_name, IIO_SFA_FILENAME)) {
+            std::string filename = device_dir;
+            filename += "/";
+            filename += ent->d_name;
+            ret = sysfs_read_str(filename, &line);
+            if (ret < 0) return ret;
+            char* pch = strtok_r(const_cast<char*>(line.c_str()), " ,", &rest);
+            while (pch != nullptr) {
+                sfa->push_back(atof(pch));
+                pch = strtok_r(nullptr, " ,", &rest);
+            }
+        }
     }
 
     return ret < 0 ? ret : 0;
 }
 
-static int get_sensor_power(const std::string& device_dir, unsigned int* power) {
-    const std::string filename = device_dir + "/" + IIO_POWER_FILENAME;
+static int get_sensor_range(const std::string& device_dir, float* resolution, int64_t* max_range) {
+    int ret = 0;
+    char* rest;
+    std::string line;
+    DirPtr dp(nullptr, closedir);
+    const struct dirent* ent;
 
-    return sysfs_read_uint(filename, power);
+    ret = sysfs_opendir(device_dir, &dp);
+    if (ret) return ret;
+    while (ent = readdir(dp.get()), ent != nullptr) {
+        if (str_has_suffix(ent->d_name, IIO_RANGE_AVAIL_FILENAME)) {
+            std::string filename = device_dir;
+            filename += "/";
+            filename += ent->d_name;
+
+            ret = sysfs_read_str(filename, &line);
+            if (ret < 0) return ret;
+            char* pch = strtok_r(const_cast<char*>(line.c_str()), " ", &rest);
+            std::vector<std::string> range_avail;
+            while (pch != nullptr) {
+                range_avail.push_back(pch);
+                pch = strtok_r(nullptr, " ", &rest);
+            }
+            *resolution = atof(range_avail[1].c_str());
+            *max_range = atoll(range_avail[2].c_str());
+        }
+    }
+
+    return ret < 0 ? ret : 0;
 }
 
-static int get_sensor_max_range(const std::string& device_dir, int64_t* max_range) {
-    const std::string filename = device_dir + "/" + IIO_MAX_RANGE_FILENAME;
+static int get_sensor_name(const std::string& device_dir, std::string* name) {
+    const std::string filename = device_dir + "/" + IIO_NAME_FILENAME;
 
-    return sysfs_read_int64(filename, max_range);
+    return sysfs_read_str(filename, name);
 }
 
 int set_sampling_frequency(const std::string& device_dir, const double frequency) {
@@ -234,54 +260,35 @@
     return err;
 }
 
-static int get_sensor_resolution(const std::string& device_dir, float* resolution) {
-    const std::string filename = device_dir + "/" + IIO_RESOLUTION_FILENAME;
-
-    return sysfs_read_float(filename, resolution);
-}
-
-static bool is_supported_sensor(const std::string& path,
-                                const std::vector<sensors_supported_hal>& supported_sensors,
-                                std::string* name, sensors_supported_hal* sensor) {
-    std::string name_file = path + "/name";
-    std::ifstream iio_file(name_file.c_str());
-    if (!iio_file) return false;
-    std::string iio_name;
-    std::getline(iio_file, iio_name);
-    auto iter = std::find_if(
-            supported_sensors.begin(), supported_sensors.end(),
-            [&iio_name](const auto& candidate) -> bool { return candidate.name == iio_name; });
-    if (iter == supported_sensors.end()) return false;
-    *sensor = *iter;
-    *name = iio_name;
-    return true;
-}
-
-int load_iio_devices(std::vector<iio_device_data>* iio_data,
-                     const std::vector<sensors_supported_hal>& supported_sensors) {
+int load_iio_devices(std::string iio_dir, std::vector<iio_device_data>* iio_data,
+                     DeviceFilterFunction filter) {
     DirPtr dp(nullptr, closedir);
     const struct dirent* ent;
     int err;
 
+    if (!iio_dir.empty() && iio_dir.back() != '/') iio_dir += '/';
+
     std::ifstream iio_file;
     const auto iio_base_len = strlen(IIO_DEVICE_BASE);
-    err = sysfs_opendir(DEVICE_IIO_DIR, &dp);
+    err = sysfs_opendir(iio_dir, &dp);
     if (err) return err;
     while (ent = readdir(dp.get()), ent != nullptr) {
         if (!str_has_prefix(ent->d_name, IIO_DEVICE_BASE)) continue;
 
-        std::string path_device = DEVICE_IIO_DIR;
+        std::string path_device = iio_dir;
         path_device += ent->d_name;
-        sensors_supported_hal sensor_match;
-        std::string iio_name;
-        if (!is_supported_sensor(path_device, supported_sensors, &iio_name, &sensor_match))
-            continue;
 
-        ALOGI("found sensor %s at path %s", iio_name.c_str(), path_device.c_str());
         iio_device_data iio_dev_data;
-        iio_dev_data.name = iio_name;
-        iio_dev_data.type = sensor_match.type;
-        iio_dev_data.sysfspath.append(path_device, 0, strlen(DEVICE_IIO_DIR) + strlen(ent->d_name));
+        iio_dev_data.sysfspath.append(path_device, 0, iio_dir.size() + strlen(ent->d_name));
+        err = get_sensor_name(iio_dev_data.sysfspath, &iio_dev_data.name);
+        if (err) {
+            ALOGE("get_sensor_name for %s returned error %d", path_device.c_str(), err);
+            continue;
+        }
+
+        if (!filter(&iio_dev_data)) continue;
+
+        ALOGI("found sensor %s at path %s", iio_dev_data.name.c_str(), path_device.c_str());
         err = get_sampling_frequency_available(iio_dev_data.sysfspath,
                                                &iio_dev_data.sampling_freq_avl);
         if (err) {
@@ -296,19 +303,10 @@
             ALOGE("get_sensor_scale for %s returned error %d", path_device.c_str(), err);
             continue;
         }
-        err = get_sensor_power(iio_dev_data.sysfspath, &iio_dev_data.power_microwatts);
+        err = get_sensor_range(iio_dev_data.sysfspath, &iio_dev_data.resolution,
+                               &iio_dev_data.max_range);
         if (err) {
-            ALOGE("get_sensor_power for %s returned error %d", path_device.c_str(), err);
-            continue;
-        }
-        err = get_sensor_max_range(iio_dev_data.sysfspath, &iio_dev_data.max_range);
-        if (err) {
-            ALOGE("get_sensor_max_range for %s returned error %d", path_device.c_str(), err);
-            continue;
-        }
-        err = get_sensor_resolution(iio_dev_data.sysfspath, &iio_dev_data.resolution);
-        if (err) {
-            ALOGE("get_sensor_resolution for %s returned error %d", path_device.c_str(), err);
+            ALOGE("get_sensor_range for %s returned error %d", path_device.c_str(), err);
             continue;
         }
 
diff --git a/hal/sensors/2.0/iio_utils.h b/hal/sensors/2.0/iio_utils.h
index 1beb5d4..a84d369 100644
--- a/hal/sensors/2.0/iio_utils.h
+++ b/hal/sensors/2.0/iio_utils.h
@@ -22,6 +22,7 @@
 #include <linux/types.h>
 #include <stdint.h>
 #include <sys/ioctl.h>
+#include <functional>
 
 namespace android {
 namespace hardware {
@@ -32,6 +33,8 @@
 
 using ::android::hardware::sensors::V1_0::SensorType;
 
+extern const char* DEFAULT_IIO_DIR;
+
 static constexpr auto DEFAULT_IIO_BUFFER_LEN = 2;
 static constexpr auto DISABLE_CHANNEL = 0;
 static constexpr auto ENABLE_CHANNEL = 1;
@@ -60,12 +63,13 @@
     std::vector<iio_info_channel> channelInfo;
     std::vector<double> sampling_freq_avl;
     uint8_t iio_dev_num;
-    unsigned int power_microwatts;
     int64_t max_range;
 };
 
-int load_iio_devices(std::vector<iio_device_data>* iio_data,
-                     const std::vector<sensors_supported_hal>& supported_sensors);
+using DeviceFilterFunction = std::function<bool(iio_device_data*)>;
+
+int load_iio_devices(std::string iio_dir, std::vector<iio_device_data>* iio_data,
+                     DeviceFilterFunction filter);
 int scan_elements(const std::string& device_dir, struct iio_device_data* iio_data);
 int enable_sensor(const std::string& name, const bool flag);
 int set_sampling_frequency(const std::string& name, const double frequency);
diff --git a/hal/sensors/2.0/tests/IioUtilsTest.cpp b/hal/sensors/2.0/tests/IioUtilsTest.cpp
new file mode 100644
index 0000000..034a6b8
--- /dev/null
+++ b/hal/sensors/2.0/tests/IioUtilsTest.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <gtest/gtest.h>
+#include <sys/stat.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <sstream>
+
+#include "iio_utils.h"
+
+using ::android::hardware::sensors::V1_0::SensorType;
+using android::hardware::sensors::V2_0::subhal::implementation::iio_device_data;
+using android::hardware::sensors::V2_0::subhal::implementation::load_iio_devices;
+using android::hardware::sensors::V2_0::subhal::implementation::sensors_supported_hal;
+
+static bool sensorFilter(iio_device_data* dev) {
+    static std::map<std::string, SensorType> KNOWN_SENSORS = {
+            {"scmi.iio.accel", SensorType::ACCELEROMETER},
+    };
+
+    if (!dev) return false;
+
+    const auto iter = KNOWN_SENSORS.find(dev->name);
+    if (iter == KNOWN_SENSORS.end()) return false;
+
+    dev->type = iter->second;
+    return true;
+}
+
+TEST(IIoUtilsTest, ScanEmptyDirectory) {
+    TemporaryDir td;
+    std::vector<iio_device_data> iio_devices;
+    const auto err = load_iio_devices(td.path, &iio_devices, sensorFilter);
+    ASSERT_EQ(0, err);
+    ASSERT_EQ(0, iio_devices.size());
+}
+
+static std::string concatPaths(const std::string& a, const std::string& b) {
+    std::stringstream ss;
+    ss << a << '/' << b;
+    return ss.str();
+}
+
+template <typename T>
+static bool writeFile(const std::string& path, const T& content, bool nl = true) {
+    std::stringstream ss;
+    ss << content;
+
+    std::ofstream f;
+    f.open(path);
+    if (!f) return false;
+    f << ss.str();
+    if (nl) f << '\n';
+    f.close();
+    return true;
+}
+
+template <typename U>
+static bool writeFile(const std::string& path, const std::vector<U>& content, bool nl = true) {
+    std::stringstream ss;
+    bool first = true;
+    for (const auto& item : content) {
+        if (!first) ss << ' ';
+        ss << item;
+        if (first) first = false;
+    }
+
+    return writeFile(path, ss.str(), nl);
+}
+
+static bool writeAccelDevice(const std::string& td_path, const iio_device_data& dev) {
+    std::stringstream ss;
+    ss << concatPaths(td_path, "iio:device") << std::to_string(dev.iio_dev_num);
+    const std::string dev_path(ss.str());
+
+    int err = mkdir(dev_path.c_str(), 0777);
+    if (err != 0) return false;
+
+    if (!writeFile(concatPaths(dev_path, "name"), dev.name)) return false;
+    if (!writeFile(concatPaths(dev_path, "in_accel_x_scale"), dev.scale)) return false;
+    if (!writeFile(concatPaths(dev_path, "in_accel_y_scale"), dev.scale)) return false;
+    if (!writeFile(concatPaths(dev_path, "in_accel_z_scale"), dev.scale)) return false;
+    if (!writeFile(concatPaths(dev_path, "in_accel_raw_available"),
+                   "[-78381056.000000000 2392.000000000 78378664.000000000]"))
+        return false;
+    if (!writeFile(concatPaths(dev_path, "in_accel_sampling_frequency_available"),
+                   dev.sampling_freq_avl))
+        return false;
+
+    return true;
+}
+
+// sets up a new iio:device<id> device with default parameters for an accelerometer
+static iio_device_data createDefaultAccelerometerDevice(int id) {
+    iio_device_data dev;
+    dev.type = SensorType::ACCELEROMETER;
+    dev.iio_dev_num = id;
+    dev.name = "scmi.iio.accel";
+    dev.sampling_freq_avl = {12.500000, 26.000364, 52.002080, 104.004160, 208.003993};
+    dev.resolution = 2392;
+    dev.scale = 0.000001000f;
+    dev.max_range = 78378664;
+
+    return dev;
+}
+
+TEST(IioUtilsTest, LoadValidSensor) {
+    TemporaryDir td;
+    const std::string td_path(td.path);
+    const auto dev_model = createDefaultAccelerometerDevice(0);
+    bool ok = writeAccelDevice(td_path, dev_model);
+    ASSERT_TRUE(ok);
+
+    std::vector<iio_device_data> iio_devices;
+    const auto err = load_iio_devices(td_path, &iio_devices, sensorFilter);
+    ASSERT_EQ(0, err);
+    ASSERT_EQ(1, iio_devices.size());
+
+    const auto& accel(iio_devices[0]);
+
+    EXPECT_EQ(SensorType::ACCELEROMETER, accel.type);
+    EXPECT_EQ("scmi.iio.accel", accel.name);
+    EXPECT_EQ(0, accel.iio_dev_num);
+
+    EXPECT_NEAR(dev_model.resolution, accel.resolution, 0.0002);
+    EXPECT_NEAR(dev_model.scale, accel.scale, 0.0002);
+    EXPECT_EQ(dev_model.max_range, accel.max_range);
+
+    EXPECT_EQ(dev_model.sampling_freq_avl.size(), accel.sampling_freq_avl.size());
+    for (size_t i = 0; i < dev_model.sampling_freq_avl.size(); ++i) {
+        if (i >= accel.sampling_freq_avl.size()) break;
+        EXPECT_NEAR(dev_model.sampling_freq_avl[i], accel.sampling_freq_avl[i], 0.0002);
+    }
+}