Created new virtual LimitedAxesImuSensor.

Updated SensorService to instantiate a new virtual
LimitedAxesImuSensor instance for each physical 3D IMU sensor
available on an automotive device.

Fix: 194217520
Bug: 194217520
Test: m sensorservice
Change-Id: Iefa4acc7fd4cc729149324c50cd63039c0af5157
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index d5b629d..3c4f8d9 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -17,6 +17,7 @@
         "Fusion.cpp",
         "GravitySensor.cpp",
         "HidlSensorHalWrapper.cpp",
+        "LimitedAxesImuSensor.cpp",
         "LinearAccelerationSensor.cpp",
         "OrientationSensor.cpp",
         "RecentEventLogger.cpp",
diff --git a/services/sensorservice/LimitedAxesImuSensor.cpp b/services/sensorservice/LimitedAxesImuSensor.cpp
new file mode 100644
index 0000000..2f91479
--- /dev/null
+++ b/services/sensorservice/LimitedAxesImuSensor.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 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 <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "LimitedAxesImuSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+#include "SensorServiceUtils.h"
+
+namespace android {
+
+namespace {
+const sensor_t DUMMY_SENSOR = {.name = "",
+                               .vendor = "",
+                               .stringType = "",
+                               .requiredPermission = ""};
+} // unnamed namespace
+
+LimitedAxesImuSensor::LimitedAxesImuSensor(sensor_t const* list, size_t count,
+                                           int32_t imu3dSensorType)
+      : BaseSensor(DUMMY_SENSOR) {
+    for (size_t i = 0; i < count; i++) {
+        if (list[i].type == imu3dSensorType) {
+            mImu3dSensor = Sensor(list + i);
+            break;
+        }
+    }
+
+    const int32_t imuLimitedAxesSensorType = convertImu3dToLimitedAxesSensorType(imu3dSensorType);
+
+    const sensor_t sensor = {
+            .name = convertLimitedAxesSensorTypeToName(imuLimitedAxesSensorType),
+            .vendor = "AOSP",
+            .version = 1,
+            .handle = convertLimitedAxesSensorTypeToHandle(imuLimitedAxesSensorType),
+            .type = imuLimitedAxesSensorType,
+            .maxRange = mImu3dSensor.getMaxValue(),
+            .resolution = mImu3dSensor.getResolution(),
+            .power = mImu3dSensor.getPowerUsage(),
+            .minDelay = mImu3dSensor.getMinDelay(),
+    };
+    mSensor = Sensor(&sensor);
+}
+
+bool LimitedAxesImuSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) {
+    if (event.type == mImu3dSensor.getType()) {
+        *outEvent = event;
+        size_t imu3dDataSize = SensorServiceUtil::eventSizeBySensorType(mImu3dSensor.getType());
+        outEvent->data[0 + imu3dDataSize] = 1;
+        outEvent->data[1 + imu3dDataSize] = 1;
+        outEvent->data[2 + imu3dDataSize] = 1;
+        outEvent->sensor = mSensor.getHandle();
+        outEvent->type = mSensor.getType();
+        return true;
+    }
+    return false;
+}
+
+status_t LimitedAxesImuSensor::activate(void* ident, bool enabled) {
+    return mSensorDevice.activate(ident, mImu3dSensor.getHandle(), enabled);
+}
+
+status_t LimitedAxesImuSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
+    return mSensorDevice.setDelay(ident, mImu3dSensor.getHandle(), ns);
+}
+
+int32_t LimitedAxesImuSensor::convertImu3dToLimitedAxesSensorType(int32_t imu3dSensorType) {
+    switch (imu3dSensorType) {
+        case SENSOR_TYPE_ACCELEROMETER:
+            return SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES;
+        case SENSOR_TYPE_GYROSCOPE:
+            return SENSOR_TYPE_GYROSCOPE_LIMITED_AXES;
+        case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
+            return SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED;
+        case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+            return SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED;
+        default:
+            return 0;
+    }
+}
+
+int32_t LimitedAxesImuSensor::convertLimitedAxesSensorTypeToHandle(
+        int32_t imuLimitedAxesSensorType) {
+    switch (imuLimitedAxesSensorType) {
+        case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
+            return '_ala';
+        case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
+            return '_gla';
+        case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+            return '_alc';
+        case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+            return '_glc';
+        default:
+            return 0;
+    }
+}
+
+const char* LimitedAxesImuSensor::convertLimitedAxesSensorTypeToName(
+        int32_t imuLimitedAxesSensorType) {
+    switch (imuLimitedAxesSensorType) {
+        case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
+            return "Accelerometer Limited Axes Sensor";
+        case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
+            return "Gyroscope Limited Axes Sensor";
+        case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+            return "Accelerometer Limited Axes Uncalibrated Sensor";
+        case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+            return "Gyroscope Limited Axes Uncalibrated Sensor";
+        default:
+            return "";
+    }
+}
+
+}; // namespace android
diff --git a/services/sensorservice/LimitedAxesImuSensor.h b/services/sensorservice/LimitedAxesImuSensor.h
new file mode 100644
index 0000000..fd46a98
--- /dev/null
+++ b/services/sensorservice/LimitedAxesImuSensor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <sensor/Sensor.h>
+
+#include "SensorInterface.h"
+
+namespace android {
+
+class SensorDevice;
+
+class LimitedAxesImuSensor : public BaseSensor {
+    Sensor mImu3dSensor;
+
+public:
+    LimitedAxesImuSensor(sensor_t const* list, size_t count, int32_t imuSensorType);
+    virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+    virtual status_t activate(void* ident, bool enabled) override;
+    virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+    virtual bool isVirtual() const override { return true; }
+
+private:
+    int32_t convertImu3dToLimitedAxesSensorType(int32_t imu3dSensorType);
+    int32_t convertLimitedAxesSensorTypeToHandle(int32_t imuLimitedAxesSensorType);
+    const char* convertLimitedAxesSensorTypeToName(int32_t imuLimitedAxesSensorType);
+};
+
+}; // namespace android
\ No newline at end of file
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 9bc7b8e..33824f2 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -38,6 +38,7 @@
 #include "BatteryService.h"
 #include "CorrectedGyroSensor.h"
 #include "GravitySensor.h"
+#include "LimitedAxesImuSensor.h"
 #include "LinearAccelerationSensor.h"
 #include "OrientationSensor.h"
 #include "RotationVectorSensor.h"
@@ -101,6 +102,33 @@
 static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
 static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
 
+static bool isAutomotive() {
+    sp<IServiceManager> serviceManager = defaultServiceManager();
+    if (serviceManager.get() == nullptr) {
+        ALOGE("%s: unable to access native ServiceManager", __func__);
+        return false;
+    }
+
+    sp<content::pm::IPackageManagerNative> packageManager;
+    sp<IBinder> binder = serviceManager->waitForService(String16("package_native"));
+    packageManager = interface_cast<content::pm::IPackageManagerNative>(binder);
+    if (packageManager == nullptr) {
+        ALOGE("%s: unable to access native PackageManager", __func__);
+        return false;
+    }
+
+    bool isAutomotive = false;
+    binder::Status status =
+        packageManager->hasSystemFeature(String16("android.hardware.type.automotive"), 0,
+                                         &isAutomotive);
+    if (!status.isOk()) {
+        ALOGE("%s: hasSystemFeature failed: %s", __func__, status.exceptionMessage().c_str());
+        return false;
+    }
+
+    return isAutomotive;
+}
+
 SensorService::SensorService()
     : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
       mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
@@ -165,6 +193,8 @@
         ssize_t count = dev.getSensorList(&list);
         if (count > 0) {
             bool hasGyro = false, hasAccel = false, hasMag = false;
+            bool hasGyroUncalibrated = false;
+            bool hasAccelUncalibrated = false;
             uint32_t virtualSensorsNeeds =
                     (1<<SENSOR_TYPE_GRAVITY) |
                     (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
@@ -179,13 +209,18 @@
                     case SENSOR_TYPE_ACCELEROMETER:
                         hasAccel = true;
                         break;
+                    case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
+                        hasAccelUncalibrated = true;
+                        break;
                     case SENSOR_TYPE_MAGNETIC_FIELD:
                         hasMag = true;
                         break;
                     case SENSOR_TYPE_GYROSCOPE:
-                    case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
                         hasGyro = true;
                         break;
+                    case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+                        hasGyroUncalibrated = true;
+                        break;
                     case SENSOR_TYPE_GRAVITY:
                     case SENSOR_TYPE_LINEAR_ACCELERATION:
                     case SENSOR_TYPE_ROTATION_VECTOR:
@@ -216,7 +251,7 @@
             // registered)
             SensorFusion::getInstance();
 
-            if (hasGyro && hasAccel && hasMag) {
+            if ((hasGyro || hasGyroUncalibrated) && hasAccel && hasMag) {
                 // Add Android virtual sensors if they're not already
                 // available in the HAL
                 bool needRotationVector =
@@ -230,7 +265,7 @@
                 registerSensor( new GyroDriftSensor(), true, true);
             }
 
-            if (hasAccel && hasGyro) {
+            if (hasAccel && (hasGyro || hasGyroUncalibrated)) {
                 bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0;
                 registerSensor(new GravitySensor(list, count), !needGravitySensor, true);
 
@@ -250,6 +285,30 @@
                 registerSensor(new GeoMagRotationVectorSensor(), !needGeoMagRotationVector, true);
             }
 
+            if (isAutomotive()) {
+                if (hasAccel) {
+                   registerSensor(new LimitedAxesImuSensor(list, count, SENSOR_TYPE_ACCELEROMETER),
+                                  /*isDebug=*/false, /*isVirtual=*/true);
+               }
+
+               if (hasGyro) {
+                   registerSensor(new LimitedAxesImuSensor(list, count, SENSOR_TYPE_GYROSCOPE),
+                                  /*isDebug=*/false, /*isVirtual=*/true);
+               }
+
+               if (hasAccelUncalibrated) {
+                   registerSensor(new LimitedAxesImuSensor(list, count,
+                                                           SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED),
+                                  /*isDebug=*/false, /*isVirtual=*/true);
+               }
+
+               if (hasGyroUncalibrated) {
+                   registerSensor(new LimitedAxesImuSensor(list, count,
+                                                           SENSOR_TYPE_GYROSCOPE_UNCALIBRATED),
+                                  /*isDebug=*/false, /*isVirtual=*/true);
+               }
+            }
+
             // Check if the device really supports batching by looking at the FIFO event
             // counts for each sensor.
             bool batchingSupported = false;