Add SensorManager support in inputflinger.
Add sensor device, sensor input mapper, sens event dispatcher support
into inputflinger.
Bug: 161634265
Test: atest inputflinger_tests
Change-Id: I2dcb2c35d9dccefc4cd8d939b79cf340931a9410
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 0ccada9..abda4ef 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -37,6 +37,7 @@
"mapper/KeyboardInputMapper.cpp",
"mapper/MultiTouchInputMapper.cpp",
"mapper/RotaryEncoderInputMapper.cpp",
+ "mapper/SensorInputMapper.cpp",
"mapper/SingleTouchInputMapper.cpp",
"mapper/SwitchInputMapper.cpp",
"mapper/TouchInputMapper.cpp",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index f864c0e..b97ff90 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -157,6 +157,18 @@
}
}
+ if (deviceClasses.test(InputDeviceClass::SENSOR)) {
+ switch (axis) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_Z:
+ case ABS_RX:
+ case ABS_RY:
+ case ABS_RZ:
+ return InputDeviceClass::SENSOR;
+ }
+ }
+
// External stylus gets the pressure axis
if (deviceClasses.test(InputDeviceClass::EXTERNAL_STYLUS)) {
if (axis == ABS_PRESSURE) {
@@ -250,6 +262,11 @@
// uses the timestamps extensively and assumes they were recorded using the monotonic
// clock.
int clockId = CLOCK_MONOTONIC;
+ if (classes.test(InputDeviceClass::SENSOR)) {
+ // Each new sensor event should use the same time base as
+ // SystemClock.elapsedRealtimeNanos().
+ clockId = CLOCK_BOOTTIME;
+ }
bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
ALOGI("usingClockIoctl=%s", toString(usingClockIoctl));
}
@@ -550,6 +567,15 @@
: false;
}
+bool EventHub::hasMscEvent(int32_t deviceId, int mscEvent) const {
+ std::scoped_lock _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ return mscEvent >= 0 && mscEvent <= MSC_MAX && device != nullptr
+ ? device->mscBitmask.test(mscEvent)
+ : false;
+}
+
int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
if (scanCode >= 0 && scanCode <= KEY_MAX) {
std::scoped_lock _l(mLock);
@@ -705,6 +731,17 @@
return NAME_NOT_FOUND;
}
+base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int32_t deviceId,
+ int32_t absCode) {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+
+ if (device != nullptr && device->keyMap.haveKeyLayout()) {
+ return device->keyMap.keyLayoutMap->mapSensor(absCode);
+ }
+ return Errorf("Device not found or device has no key layout.");
+}
+
void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
std::scoped_lock _l(mLock);
@@ -1405,6 +1442,7 @@
device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0), device->swBitmask);
device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0), device->ledBitmask);
device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0), device->ffBitmask);
+ device->readDeviceBitMask(EVIOCGBIT(EV_MSC, 0), device->mscBitmask);
device->readDeviceBitMask(EVIOCGPROP(0), device->propBitmask);
// See if this is a keyboard. Ignore everything in the button range except for
@@ -1469,6 +1507,11 @@
}
}
+ // Check whether this device is an accelerometer.
+ if (device->propBitmask.test(INPUT_PROP_ACCELEROMETER)) {
+ device->classes |= InputDeviceClass::SENSOR;
+ }
+
// Check whether this device has switches.
for (int i = 0; i <= SW_MAX; i++) {
if (device->swBitmask.test(i)) {
@@ -1493,9 +1536,11 @@
}
// Load the key map.
- // We need to do this for joysticks too because the key layout may specify axes.
+ // We need to do this for joysticks too because the key layout may specify axes, and for
+ // sensor as well because the key layout may specify the axes to sensor data mapping.
status_t keyMapStatus = NAME_NOT_FOUND;
- if (device->classes.any(InputDeviceClass::KEYBOARD | InputDeviceClass::JOYSTICK)) {
+ if (device->classes.any(InputDeviceClass::KEYBOARD | InputDeviceClass::JOYSTICK |
+ InputDeviceClass::SENSOR)) {
// Load the keymap for the device.
keyMapStatus = device->loadKeyMapLocked();
}
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index d25d64a..ac72ac4 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -28,6 +28,7 @@
#include "KeyboardInputMapper.h"
#include "MultiTouchInputMapper.h"
#include "RotaryEncoderInputMapper.h"
+#include "SensorInputMapper.h"
#include "SingleTouchInputMapper.h"
#include "SwitchInputMapper.h"
#include "VibratorInputMapper.h"
@@ -196,6 +197,11 @@
mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
}
+ // Motion sensor enabled devices.
+ if (classes.test(InputDeviceClass::SENSOR)) {
+ mappers.push_back(std::make_unique<SensorInputMapper>(*contextPtr));
+ }
+
// External stylus-like devices.
if (classes.test(InputDeviceClass::EXTERNAL_STYLUS)) {
mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
@@ -460,6 +466,25 @@
return vibrators;
}
+bool InputDevice::enableSensor(InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) {
+ bool success = true;
+ for_each_mapper(
+ [&success, sensorType, samplingPeriod, maxBatchReportLatency](InputMapper& mapper) {
+ success &= mapper.enableSensor(sensorType, samplingPeriod, maxBatchReportLatency);
+ });
+ return success;
+}
+
+void InputDevice::disableSensor(InputDeviceSensorType sensorType) {
+ for_each_mapper([sensorType](InputMapper& mapper) { mapper.disableSensor(sensorType); });
+}
+
+void InputDevice::flushSensor(InputDeviceSensorType sensorType) {
+ for_each_mapper([sensorType](InputMapper& mapper) { mapper.flushSensor(sensorType); });
+}
+
void InputDevice::cancelTouch(nsecs_t when) {
for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); });
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index a6b5e2d..be21ace 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -220,6 +220,11 @@
if (device->getClasses().test(InputDeviceClass::EXTERNAL_STYLUS)) {
notifyExternalStylusPresenceChangedLocked();
}
+
+ // Sensor input device is noisy, to save power disable it by default.
+ if (device->getClasses().test(InputDeviceClass::SENSOR)) {
+ mEventHub->disableDevice(eventHubId);
+ }
}
void InputReader::removeDeviceLocked(nsecs_t when, int32_t eventHubId) {
@@ -639,6 +644,36 @@
return {};
}
+void InputReader::disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ device->disableSensor(sensorType);
+ }
+}
+
+bool InputReader::enableSensor(int32_t deviceId, InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ return device->enableSensor(sensorType, samplingPeriod, maxBatchReportLatency);
+ }
+ return false;
+}
+
+void InputReader::flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (device) {
+ device->flushSensor(sensorType);
+ }
+}
+
bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 9e38d0a..2cea017 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -118,6 +118,9 @@
/* The input device has a rotary encoder */
ROTARY_ENCODER = 0x00001000,
+ /* The input device has a sensor like accelerometer, gyro, etc */
+ SENSOR = 0x00002000,
+
/* The input device is virtual (not a real device, not part of UI configuration). */
VIRTUAL = 0x40000000,
@@ -177,6 +180,8 @@
virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
+ virtual bool hasMscEvent(int32_t deviceId, int mscEvent) const = 0;
+
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
int32_t metaState, int32_t* outKeycode, int32_t* outMetaState,
uint32_t* outFlags) const = 0;
@@ -201,6 +206,8 @@
*/
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0;
+ virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
+ int32_t absCode) = 0;
/*
* Query current input state.
@@ -346,6 +353,8 @@
bool hasInputProperty(int32_t deviceId, int property) const override final;
+ bool hasMscEvent(int32_t deviceId, int mscEvent) const override final;
+
status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState,
uint32_t* outFlags) const override final;
@@ -353,6 +362,9 @@
status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const override final;
+ base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
+ int32_t deviceId, int32_t absCode) override final;
+
void setExcludedDevices(const std::vector<std::string>& devices) override final;
int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override final;
@@ -420,6 +432,7 @@
BitArray<LED_MAX> ledBitmask;
BitArray<FF_MAX> ffBitmask;
BitArray<INPUT_PROP_MAX> propBitmask;
+ BitArray<MSC_MAX> mscBitmask;
std::string configurationFile;
std::unique_ptr<PropertyMap> configuration;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 8b14b06..5af76b7 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -87,6 +87,10 @@
bool isVibrating();
std::vector<int32_t> getVibratorIds();
void cancelTouch(nsecs_t when);
+ bool enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency);
+ void disableSensor(InputDeviceSensorType sensorType);
+ void flushSensor(InputDeviceSensorType sensorType);
int32_t getMetaState();
void updateMetaState(int32_t keyCode);
@@ -229,9 +233,12 @@
inline bool hasRelativeAxis(int32_t code) const {
return mEventHub->hasRelativeAxis(mId, code);
}
- inline bool hasInputProperty(int property) const {
+ inline bool hasInputProperty(int32_t property) const {
return mEventHub->hasInputProperty(mId, property);
}
+
+ inline bool hasMscEvent(int mscEvent) const { return mEventHub->hasMscEvent(mId, mscEvent); }
+
inline status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
return mEventHub->mapKey(mId, scanCode, usageCode, metaState, outKeycode, outMetaState,
@@ -240,6 +247,10 @@
inline status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
return mEventHub->mapAxis(mId, scanCode, outAxisInfo);
}
+ inline base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode) {
+ return mEventHub->mapSensor(mId, absCode);
+ }
+
inline std::vector<TouchVideoFrame> getVideoFrames() { return mEventHub->getVideoFrames(mId); }
inline int32_t getScanCodeState(int32_t scanCode) const {
return mEventHub->getScanCodeState(mId, scanCode);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index b16b86c..48d4596 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -87,6 +87,14 @@
bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) override;
+ bool enableSensor(int32_t deviceId, InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) override;
+
+ void disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) override;
+
+ void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 913cef7..1ce54ae 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -70,6 +70,16 @@
void InputMapper::cancelTouch(nsecs_t when) {}
+bool InputMapper::enableSensor(InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) {
+ return true;
+}
+
+void InputMapper::disableSensor(InputDeviceSensorType sensorType) {}
+
+void InputMapper::flushSensor(InputDeviceSensorType sensorType) {}
+
int32_t InputMapper::getMetaState() {
return 0;
}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 088dbd8..bd64d8d 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -68,6 +68,11 @@
virtual bool isVibrating();
virtual std::vector<int32_t> getVibratorIds();
virtual void cancelTouch(nsecs_t when);
+ virtual bool enableSensor(InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency);
+ virtual void disableSensor(InputDeviceSensorType sensorType);
+ virtual void flushSensor(InputDeviceSensorType sensorType);
virtual int32_t getMetaState();
virtual void updateMetaState(int32_t keyCode);
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
new file mode 100644
index 0000000..7d97014
--- /dev/null
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 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 <locale>
+
+#include "../Macros.h"
+
+#include "SensorInputMapper.h"
+
+// Log detailed debug messages about each sensor event notification to the dispatcher.
+constexpr bool DEBUG_SENSOR_EVENT_DETAILS = false;
+
+namespace android {
+
+// Mask for the LSB 2nd, 3rd and fourth bits.
+constexpr int REPORTING_MODE_MASK = 0xE;
+constexpr int REPORTING_MODE_SHIFT = 1;
+constexpr float GRAVITY_MS2_UNIT = 9.80665f;
+constexpr float DEGREE_RADIAN_UNIT = 0.0174533f;
+
+/* Convert the sensor data from Linux to Android
+ * Linux accelerometer unit is per g, Android unit is m/s^2
+ * Linux gyroscope unit is degree/second, Android unit is radians/second
+ */
+static void convertFromLinuxToAndroid(std::vector<float>& values,
+ InputDeviceSensorType sensorType) {
+ for (size_t i = 0; i < values.size(); i++) {
+ switch (sensorType) {
+ case InputDeviceSensorType::ACCELEROMETER:
+ values[i] *= GRAVITY_MS2_UNIT;
+ break;
+ case InputDeviceSensorType::GYROSCOPE:
+ values[i] *= DEGREE_RADIAN_UNIT;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+SensorInputMapper::SensorInputMapper(InputDeviceContext& deviceContext)
+ : InputMapper(deviceContext) {}
+
+SensorInputMapper::~SensorInputMapper() {}
+
+uint32_t SensorInputMapper::getSources() {
+ return AINPUT_SOURCE_SENSOR;
+}
+
+template <typename T>
+bool SensorInputMapper::tryGetProperty(std::string keyName, T& outValue) {
+ const auto& config = getDeviceContext().getConfiguration();
+ return config.tryGetProperty(String8(keyName.c_str()), outValue);
+}
+
+void SensorInputMapper::parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode,
+ int32_t sensorDataIndex, const Axis& axis) {
+ auto it = mSensors.find(sensorType);
+ if (it == mSensors.end()) {
+ Sensor sensor = createSensor(sensorType, axis);
+ sensor.dataVec[sensorDataIndex] = absCode;
+ mSensors.emplace(sensorType, sensor);
+ } else {
+ it->second.dataVec[sensorDataIndex] = absCode;
+ }
+}
+
+void SensorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ for (const auto& [sensorType, sensor] : mSensors) {
+ info->addSensorInfo(sensor.sensorInfo);
+ info->setHasSensor(true);
+ }
+}
+
+void SensorInputMapper::dump(std::string& dump) {
+ dump += INDENT2 "Sensor Input Mapper:\n";
+ dump += StringPrintf(INDENT3 " isDeviceEnabled %d\n", getDeviceContext().isDeviceEnabled());
+ dump += StringPrintf(INDENT3 " mHasHardwareTimestamp %d\n", mHasHardwareTimestamp);
+ dump += INDENT3 "Sensors:\n";
+ for (const auto& [sensorType, sensor] : mSensors) {
+ dump += StringPrintf(INDENT4 "%s\n", NamedEnum::string(sensorType).c_str());
+ dump += StringPrintf(INDENT5 "enabled: %d\n", sensor.enabled);
+ dump += StringPrintf(INDENT5 "samplingPeriod: %lld\n", sensor.samplingPeriod.count());
+ dump += StringPrintf(INDENT5 "maxBatchReportLatency: %lld\n",
+ sensor.maxBatchReportLatency.count());
+ dump += StringPrintf(INDENT5 "maxRange: %f\n", sensor.sensorInfo.maxRange);
+ dump += StringPrintf(INDENT5 "power: %f\n", sensor.sensorInfo.power);
+ for (ssize_t i = 0; i < SENSOR_VEC_LEN; i++) {
+ int32_t rawAxis = sensor.dataVec[i];
+ dump += StringPrintf(INDENT5 "[%zd]: rawAxis: %d \n", i, rawAxis);
+ const auto it = mAxes.find(rawAxis);
+ if (it != mAxes.end()) {
+ const Axis& axis = it->second;
+ dump += StringPrintf(INDENT5 " min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f,"
+ "resolution=%0.5f\n",
+ axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
+ dump += StringPrintf(INDENT5 " scale=%0.5f, offset=%0.5f\n", axis.scale,
+ axis.offset);
+ dump += StringPrintf(INDENT5 " rawMin=%d, rawMax=%d, "
+ "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
+ axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
+ axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz,
+ axis.rawAxisInfo.resolution);
+ }
+ }
+ }
+}
+
+void SensorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) {
+ InputMapper::configure(when, config, changes);
+
+ if (!changes) { // first time only
+ mDeviceEnabled = true;
+ // Check if device has MSC_TIMESTAMP event.
+ mHasHardwareTimestamp = getDeviceContext().hasMscEvent(MSC_TIMESTAMP);
+ // Collect all axes.
+ for (int32_t abs = ABS_X; abs <= ABS_MAX; abs++) {
+ // axis must be claimed by sensor class device
+ if (!(getAbsAxisUsage(abs, getDeviceContext().getDeviceClasses())
+ .test(InputDeviceClass::SENSOR))) {
+ continue;
+ }
+ RawAbsoluteAxisInfo rawAxisInfo;
+ getAbsoluteAxisInfo(abs, &rawAxisInfo);
+ if (rawAxisInfo.valid) {
+ AxisInfo axisInfo;
+ // Axis doesn't need to be mapped, as sensor mapper doesn't generate any motion
+ // input events
+ axisInfo.mode = AxisInfo::MODE_NORMAL;
+ axisInfo.axis = -1;
+ // Check key layout map for sensor data mapping to axes
+ auto ret = getDeviceContext().mapSensor(abs);
+ if (ret) {
+ InputDeviceSensorType sensorType = (*ret).first;
+ int32_t sensorDataIndex = (*ret).second;
+ const Axis& axis = createAxis(axisInfo, rawAxisInfo);
+ parseSensorConfiguration(sensorType, abs, sensorDataIndex, axis);
+
+ mAxes.insert({abs, axis});
+ }
+ }
+ }
+ }
+}
+
+SensorInputMapper::Axis SensorInputMapper::createAxis(const AxisInfo& axisInfo,
+ const RawAbsoluteAxisInfo& rawAxisInfo) {
+ // Apply flat override.
+ int32_t rawFlat = axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride;
+
+ float scale = std::numeric_limits<float>::signaling_NaN();
+ float offset = 0;
+
+ // resolution is 1 of sensor's unit. For accelerometer, it is G, for gyroscope,
+ // it is degree/s.
+ scale = 1.0f / rawAxisInfo.resolution;
+ offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
+
+ const float max = rawAxisInfo.maxValue / rawAxisInfo.resolution;
+ const float min = rawAxisInfo.minValue / rawAxisInfo.resolution;
+ const float flat = rawFlat * scale;
+ const float fuzz = rawAxisInfo.fuzz * scale;
+ const float resolution = rawAxisInfo.resolution;
+
+ // To eliminate noise while the Sensor is at rest, filter out small variations
+ // in axis values up front.
+ const float filter = fuzz ? fuzz : flat * 0.25f;
+ return Axis(rawAxisInfo, axisInfo, scale, offset, min, max, flat, fuzz, resolution, filter);
+}
+
+void SensorInputMapper::reset(nsecs_t when) {
+ // Recenter all axes.
+ for (std::pair<const int32_t, Axis>& pair : mAxes) {
+ Axis& axis = pair.second;
+ axis.resetValue();
+ }
+ mHardwareTimestamp = 0;
+ mPrevMscTime = 0;
+ InputMapper::reset(when);
+}
+
+SensorInputMapper::Sensor SensorInputMapper::createSensor(InputDeviceSensorType sensorType,
+ const Axis& axis) {
+ InputDeviceIdentifier identifier = getDeviceContext().getDeviceIdentifier();
+ // Sensor Id will be assigned to device Id to distinguish same sensor from multiple input
+ // devices, in such a way that the sensor Id will be same as input device Id.
+ // The sensorType is to distinguish different sensors within one device.
+ // One input device can only have 1 sensor for each sensor Type.
+ InputDeviceSensorInfo sensorInfo(identifier.name, std::to_string(identifier.vendor),
+ identifier.version, sensorType,
+ InputDeviceSensorAccuracy::ACCURACY_HIGH,
+ axis.max /* maxRange */, axis.scale /* resolution */,
+ 0.0f /* power */, 0 /* minDelay */,
+ 0 /* fifoReservedEventCount */, 0 /* fifoMaxEventCount */,
+ NamedEnum::string(sensorType), 0 /* maxDelay */, 0 /* flags */,
+ getDeviceId());
+
+ std::string prefix = "sensor." + NamedEnum::string(sensorType);
+ transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
+
+ int32_t reportingMode = 0;
+ if (!tryGetProperty(prefix + ".reportingMode", reportingMode)) {
+ sensorInfo.flags |= (reportingMode & REPORTING_MODE_MASK) << REPORTING_MODE_SHIFT;
+ }
+
+ tryGetProperty(prefix + ".maxDelay", sensorInfo.maxDelay);
+
+ tryGetProperty(prefix + ".minDelay", sensorInfo.minDelay);
+
+ tryGetProperty(prefix + ".power", sensorInfo.power);
+
+ tryGetProperty(prefix + ".fifoReservedEventCount", sensorInfo.fifoReservedEventCount);
+
+ tryGetProperty(prefix + ".fifoMaxEventCount", sensorInfo.fifoMaxEventCount);
+
+ return Sensor(sensorInfo);
+}
+
+void SensorInputMapper::processHardWareTimestamp(nsecs_t evTime, int32_t mscTime) {
+ // Since MSC_TIMESTAMP initial state is different from the system time, we
+ // calculate the difference between two MSC_TIMESTAMP events, and use that
+ // to calculate the system time that should be tagged on the event.
+ // if the first time MSC_TIMESTAMP, store it
+ // else calculate difference between previous and current MSC_TIMESTAMP
+ if (mPrevMscTime == 0) {
+ mHardwareTimestamp = evTime;
+ if (DEBUG_SENSOR_EVENT_DETAILS) {
+ ALOGD("Initialize hardware timestamp = %" PRId64, mHardwareTimestamp);
+ }
+ } else {
+ // Calculate the difference between current msc_timestamp and
+ // previous msc_timestamp, including when msc_timestamp wraps around.
+ uint32_t timeDiff = (mPrevMscTime > static_cast<uint32_t>(mscTime))
+ ? (UINT32_MAX - mPrevMscTime + static_cast<uint32_t>(mscTime + 1))
+ : (static_cast<uint32_t>(mscTime) - mPrevMscTime);
+
+ mHardwareTimestamp += timeDiff * 1000LL;
+ }
+ mPrevMscTime = static_cast<uint32_t>(mscTime);
+}
+
+void SensorInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_ABS: {
+ auto it = mAxes.find(rawEvent->code);
+ if (it != mAxes.end()) {
+ Axis& axis = it->second;
+ axis.newValue = rawEvent->value * axis.scale + axis.offset;
+ }
+ break;
+ }
+
+ case EV_SYN:
+ switch (rawEvent->code) {
+ case SYN_REPORT:
+ for (std::pair<const int32_t, Axis>& pair : mAxes) {
+ Axis& axis = pair.second;
+ axis.currentValue = axis.newValue;
+ }
+ sync(rawEvent->when, false /*force*/);
+ break;
+ }
+ break;
+
+ case EV_MSC:
+ switch (rawEvent->code) {
+ case MSC_TIMESTAMP:
+ // hardware timestamp is nano seconds
+ processHardWareTimestamp(rawEvent->when, rawEvent->value);
+ break;
+ }
+ }
+}
+
+bool SensorInputMapper::setSensorEnabled(InputDeviceSensorType sensorType, bool enabled) {
+ auto it = mSensors.find(sensorType);
+ if (it == mSensors.end()) {
+ return false;
+ }
+
+ it->second.enabled = enabled;
+ if (!enabled) {
+ it->second.resetValue();
+ }
+
+ /* Currently we can't enable/disable sensors individually. Enabling any sensor will enable
+ * the device
+ */
+ mDeviceEnabled = false;
+ for (const auto& [sensorType, sensor] : mSensors) {
+ // If any sensor is on we will turn on the device.
+ if (sensor.enabled) {
+ mDeviceEnabled = true;
+ break;
+ }
+ }
+ return true;
+}
+
+void SensorInputMapper::flushSensor(InputDeviceSensorType sensorType) {
+ auto it = mSensors.find(sensorType);
+ if (it == mSensors.end()) {
+ return;
+ }
+ auto& sensor = it->second;
+ sensor.lastSampleTimeNs = 0;
+ for (size_t i = 0; i < SENSOR_VEC_LEN; i++) {
+ int32_t abs = sensor.dataVec[i];
+ auto itAxis = mAxes.find(abs);
+ if (itAxis != mAxes.end()) {
+ Axis& axis = itAxis->second;
+ axis.resetValue();
+ }
+ }
+}
+
+bool SensorInputMapper::enableSensor(InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) {
+ if (DEBUG_SENSOR_EVENT_DETAILS) {
+ ALOGD("Enable Sensor %s samplingPeriod %lld maxBatchReportLatency %lld",
+ NamedEnum::string(sensorType).c_str(), samplingPeriod.count(),
+ maxBatchReportLatency.count());
+ }
+
+ if (!setSensorEnabled(sensorType, true /* enabled */)) {
+ return false;
+ }
+
+ // Enable device
+ if (mDeviceEnabled) {
+ getDeviceContext().enableDevice();
+ }
+
+ // We know the sensor exists now, update the sampling period and batch report latency.
+ auto it = mSensors.find(sensorType);
+ it->second.samplingPeriod =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(samplingPeriod);
+ it->second.maxBatchReportLatency =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(maxBatchReportLatency);
+ return true;
+}
+
+void SensorInputMapper::disableSensor(InputDeviceSensorType sensorType) {
+ if (DEBUG_SENSOR_EVENT_DETAILS) {
+ ALOGD("Disable Sensor %s", NamedEnum::string(sensorType).c_str());
+ }
+
+ if (!setSensorEnabled(sensorType, false /* enabled */)) {
+ return;
+ }
+
+ // Disable device
+ if (!mDeviceEnabled) {
+ mHardwareTimestamp = 0;
+ mPrevMscTime = 0;
+ getDeviceContext().disableDevice();
+ }
+}
+
+void SensorInputMapper::sync(nsecs_t when, bool force) {
+ for (auto& [sensorType, sensor] : mSensors) {
+ // Skip if sensor not enabled
+ if (!sensor.enabled) {
+ continue;
+ }
+ std::vector<float> values;
+ for (ssize_t i = 0; i < SENSOR_VEC_LEN; i++) {
+ int32_t abs = sensor.dataVec[i];
+ auto it = mAxes.find(abs);
+ if (it != mAxes.end()) {
+ const Axis& axis = it->second;
+ values.push_back(axis.currentValue);
+ }
+ }
+
+ nsecs_t timestamp = mHasHardwareTimestamp ? mHardwareTimestamp : when;
+ if (DEBUG_SENSOR_EVENT_DETAILS) {
+ ALOGD("Sensor %s timestamp %" PRIu64 " values [%f %f %f]",
+ NamedEnum::string(sensorType).c_str(), timestamp, values[0], values[1],
+ values[2]);
+ }
+ if (sensor.lastSampleTimeNs.has_value() &&
+ timestamp - sensor.lastSampleTimeNs.value() < sensor.samplingPeriod.count()) {
+ if (DEBUG_SENSOR_EVENT_DETAILS) {
+ ALOGD("Sensor %s Skip a sample.", NamedEnum::string(sensorType).c_str());
+ }
+ } else {
+ // Convert to Android unit
+ convertFromLinuxToAndroid(values, sensorType);
+ // Notify dispatcher for sensor event
+ NotifySensorArgs args(getContext()->getNextId(), when, getDeviceId(),
+ AINPUT_SOURCE_SENSOR, sensorType, sensor.sensorInfo.accuracy,
+ sensor.accuracy !=
+ sensor.sensorInfo.accuracy /* accuracyChanged */,
+ timestamp /* hwTimestamp */, values);
+
+ getListener()->notifySensor(&args);
+ sensor.lastSampleTimeNs = timestamp;
+ sensor.accuracy = sensor.sensorInfo.accuracy;
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h
new file mode 100644
index 0000000..3371002
--- /dev/null
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
+#define _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
+
+#include "InputMapper.h"
+
+namespace android {
+// sensor data vector length
+static constexpr ssize_t SENSOR_VEC_LEN = 3;
+
+class SensorInputMapper : public InputMapper {
+public:
+ explicit SensorInputMapper(InputDeviceContext& deviceContext);
+ ~SensorInputMapper() override;
+
+ uint32_t getSources() override;
+ void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void dump(std::string& dump) override;
+ void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
+ void reset(nsecs_t when) override;
+ void process(const RawEvent* rawEvent) override;
+ bool enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) override;
+ void disableSensor(InputDeviceSensorType sensorType) override;
+ void flushSensor(InputDeviceSensorType sensorType) override;
+
+private:
+ struct Axis {
+ explicit Axis(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, float scale,
+ float offset, float min, float max, float flat, float fuzz, float resolution,
+ float filter)
+ : rawAxisInfo(rawAxisInfo),
+ axisInfo(axisInfo),
+ scale(scale),
+ offset(offset),
+ min(min),
+ max(max),
+ flat(flat),
+ fuzz(fuzz),
+ resolution(resolution),
+ filter(filter) {
+ resetValue();
+ }
+
+ RawAbsoluteAxisInfo rawAxisInfo;
+ AxisInfo axisInfo;
+
+ float scale; // scale factor from raw to normalized values
+ float offset; // offset to add after scaling for normalization
+
+ float min; // normalized inclusive minimum
+ float max; // normalized inclusive maximum
+ float flat; // normalized flat region size
+ float fuzz; // normalized error tolerance
+ float resolution; // normalized resolution in units
+
+ float filter; // filter out small variations of this size
+ float currentValue; // current value
+ float newValue; // most recent value
+
+ void resetValue() {
+ this->currentValue = 0;
+ this->newValue = 0;
+ }
+ };
+
+ struct Sensor {
+ explicit Sensor(const InputDeviceSensorInfo& sensorInfo) : sensorInfo(sensorInfo) {
+ resetValue();
+ }
+ bool enabled;
+ InputDeviceSensorAccuracy accuracy;
+ std::chrono::nanoseconds samplingPeriod;
+ std::chrono::nanoseconds maxBatchReportLatency;
+ // last sample time in nano seconds
+ std::optional<nsecs_t> lastSampleTimeNs;
+ InputDeviceSensorInfo sensorInfo;
+ // Sensor X, Y, Z data mapping to abs
+ std::array<int32_t, SENSOR_VEC_LEN> dataVec;
+ void resetValue() {
+ this->enabled = false;
+ this->accuracy = InputDeviceSensorAccuracy::ACCURACY_NONE;
+ this->samplingPeriod = std::chrono::nanoseconds(0);
+ this->maxBatchReportLatency = std::chrono::nanoseconds(0);
+ this->lastSampleTimeNs = std::nullopt;
+ this->dataVec.fill(0);
+ }
+ };
+
+ static Axis createAxis(const AxisInfo& AxisInfo, const RawAbsoluteAxisInfo& rawAxisInfo);
+
+ // Axes indexed by raw ABS_* axis index.
+ std::unordered_map<int32_t, Axis> mAxes;
+
+ // hardware timestamp from MSC_TIMESTAMP
+ nsecs_t mHardwareTimestamp;
+ uint32_t mPrevMscTime;
+
+ bool mDeviceEnabled;
+ // Does device support MSC_TIMESTAMP
+ bool mHasHardwareTimestamp;
+
+ // Sensor list
+ std::unordered_map<InputDeviceSensorType, Sensor> mSensors;
+
+ void sync(nsecs_t when, bool force);
+
+ template <typename T>
+ bool tryGetProperty(std::string keyName, T& outValue);
+
+ void parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode,
+ int32_t sensorDataIndex, const Axis& axis);
+
+ void processHardWareTimestamp(nsecs_t evTime, int32_t evValue);
+
+ Sensor createSensor(InputDeviceSensorType sensorType, const Axis& axis);
+
+ bool setSensorEnabled(InputDeviceSensorType sensorType, bool enabled);
+};
+
+} // namespace android
+
+#endif // _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
\ No newline at end of file