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/include/android/input.h b/include/android/input.h
index 38af89a..b5d399e 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -856,6 +856,8 @@
     AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
     /** joystick */
     AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
+    /** sensor */
+    AINPUT_SOURCE_SENSOR = 0x02000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
     /** rotary encoder */
     AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE,
 
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 60638ca..23692e9 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -17,8 +17,10 @@
 #ifndef _LIBINPUT_INPUT_DEVICE_H
 #define _LIBINPUT_INPUT_DEVICE_H
 
+#include <android/sensor.h>
 #include <input/Input.h>
 #include <input/KeyCharacterMap.h>
+#include <unordered_map>
 #include <vector>
 
 namespace android {
@@ -63,6 +65,97 @@
     std::string getCanonicalName() const;
 };
 
+/* Types of input device sensors. Keep sync with core/java/android/hardware/Sensor.java */
+enum class InputDeviceSensorType : int32_t {
+    ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER,
+    MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD,
+    ORIENTATION = 3,
+    GYROSCOPE = ASENSOR_TYPE_GYROSCOPE,
+    LIGHT = ASENSOR_TYPE_LIGHT,
+    PRESSURE = ASENSOR_TYPE_PRESSURE,
+    TEMPERATURE = 7,
+    PROXIMITY = ASENSOR_TYPE_PROXIMITY,
+    GRAVITY = ASENSOR_TYPE_GRAVITY,
+    LINEAR_ACCELERATION = ASENSOR_TYPE_LINEAR_ACCELERATION,
+    ROTATION_VECTOR = ASENSOR_TYPE_ROTATION_VECTOR,
+    RELATIVE_HUMIDITY = ASENSOR_TYPE_RELATIVE_HUMIDITY,
+    AMBIENT_TEMPERATURE = ASENSOR_TYPE_AMBIENT_TEMPERATURE,
+    MAGNETIC_FIELD_UNCALIBRATED = ASENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
+    GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR,
+    GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
+    SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION,
+};
+
+enum class InputDeviceSensorAccuracy : int32_t {
+    ACCURACY_NONE = 0,
+    ACCURACY_LOW = 1,
+    ACCURACY_MEDIUM = 2,
+    ACCURACY_HIGH = 3,
+};
+
+enum class InputDeviceSensorReportingMode : int32_t {
+    CONTINUOUS = 0,
+    ON_CHANGE = 1,
+    ONE_SHOT = 2,
+    SPECIAL_TRIGGER = 3,
+};
+
+struct InputDeviceSensorInfo {
+    explicit InputDeviceSensorInfo(std::string name, std::string vendor, int32_t version,
+                                   InputDeviceSensorType type, InputDeviceSensorAccuracy accuracy,
+                                   float maxRange, float resolution, float power, int32_t minDelay,
+                                   int32_t fifoReservedEventCount, int32_t fifoMaxEventCount,
+                                   std::string stringType, int32_t maxDelay, int32_t flags,
+                                   int32_t id)
+          : name(name),
+            vendor(vendor),
+            version(version),
+            type(type),
+            accuracy(accuracy),
+            maxRange(maxRange),
+            resolution(resolution),
+            power(power),
+            minDelay(minDelay),
+            fifoReservedEventCount(fifoReservedEventCount),
+            fifoMaxEventCount(fifoMaxEventCount),
+            stringType(stringType),
+            maxDelay(maxDelay),
+            flags(flags),
+            id(id) {}
+    // Name string of the sensor.
+    std::string name;
+    // Vendor string of this sensor.
+    std::string vendor;
+    // Version of the sensor's module.
+    int32_t version;
+    // Generic type of this sensor.
+    InputDeviceSensorType type;
+    // The current accuracy of sensor event.
+    InputDeviceSensorAccuracy accuracy;
+    // Maximum range of the sensor in the sensor's unit.
+    float maxRange;
+    // Resolution of the sensor in the sensor's unit.
+    float resolution;
+    // The power in mA used by this sensor while in use.
+    float power;
+    // The minimum delay allowed between two events in microsecond or zero if this sensor only
+    // returns a value when the data it's measuring changes.
+    int32_t minDelay;
+    // Number of events reserved for this sensor in the batch mode FIFO.
+    int32_t fifoReservedEventCount;
+    // Maximum number of events of this sensor that could be batched.
+    int32_t fifoMaxEventCount;
+    // The type of this sensor as a string.
+    std::string stringType;
+    // The delay between two sensor events corresponding to the lowest frequency that this sensor
+    // supports.
+    int32_t maxDelay;
+    // Sensor flags
+    int32_t flags;
+    // Sensor id, same as the input device ID it belongs to.
+    int32_t id;
+};
+
 /*
  * Describes the characteristics and capabilities of an input device.
  */
@@ -104,6 +197,7 @@
     void addMotionRange(int32_t axis, uint32_t source,
             float min, float max, float flat, float fuzz, float resolution);
     void addMotionRange(const MotionRange& range);
+    void addSensorInfo(const InputDeviceSensorInfo& info);
 
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
@@ -122,10 +216,17 @@
     inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; }
     inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; }
 
+    inline void setHasSensor(bool hasSensor) { mHasSensor = hasSensor; }
+    inline bool hasSensor() const { return mHasSensor; }
+
     inline const std::vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
 
+    const InputDeviceSensorInfo* getSensorInfo(InputDeviceSensorType type);
+
+    const std::vector<InputDeviceSensorType> getSensorTypes();
+
 private:
     int32_t mId;
     int32_t mGeneration;
@@ -139,8 +240,10 @@
     std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
     bool mHasVibrator;
     bool mHasButtonUnderPad;
+    bool mHasSensor;
 
     std::vector<MotionRange> mMotionRanges;
+    std::unordered_map<InputDeviceSensorType, InputDeviceSensorInfo> mSensors;
 };
 
 /* Types of input device configuration files. */
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 23f8ddf..451ca3c 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -142,6 +142,8 @@
     void writeToParcel(Parcel* parcel) const;
 #endif
 
+    bool operator==(const KeyCharacterMap& other) const;
+
     KeyCharacterMap(const KeyCharacterMap& other);
 
     virtual ~KeyCharacterMap();
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 872dd45..b2bd535 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -24,6 +24,8 @@
 #include <utils/RefBase.h>
 #include <utils/Tokenizer.h>
 
+#include <input/InputDevice.h>
+
 namespace android {
 
 struct AxisInfo {
@@ -76,6 +78,8 @@
 
     status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
     const std::string getLoadFileName() const;
+    // Return pair of sensor type and sensor data index, for the input device abs code
+    base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t absCode);
 
     virtual ~KeyLayoutMap();
 
@@ -89,12 +93,17 @@
         int32_t ledCode;
     };
 
+    struct Sensor {
+        InputDeviceSensorType sensorType;
+        int32_t sensorDataIndex;
+    };
 
     KeyedVector<int32_t, Key> mKeysByScanCode;
     KeyedVector<int32_t, Key> mKeysByUsageCode;
     KeyedVector<int32_t, AxisInfo> mAxes;
     KeyedVector<int32_t, Led> mLedsByScanCode;
     KeyedVector<int32_t, Led> mLedsByUsageCode;
+    std::unordered_map<int32_t, Sensor> mSensorsByAbsCode;
     std::string mLoadFileName;
 
     KeyLayoutMap();
@@ -114,6 +123,7 @@
         status_t parseKey();
         status_t parseAxis();
         status_t parseLed();
+        status_t parseSensor();
     };
 };
 
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 34eba5b..2ed441d 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -23,6 +23,7 @@
 #include <android-base/stringprintf.h>
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
+#include <input/NamedEnum.h>
 
 using android::base::StringPrintf;
 
@@ -166,7 +167,9 @@
         mKeyCharacterMap(other.mKeyCharacterMap),
         mHasVibrator(other.mHasVibrator),
         mHasButtonUnderPad(other.mHasButtonUnderPad),
-        mMotionRanges(other.mMotionRanges) {}
+        mHasSensor(other.mHasSensor),
+        mMotionRanges(other.mMotionRanges),
+        mSensors(other.mSensors) {}
 
 InputDeviceInfo::~InputDeviceInfo() {
 }
@@ -185,7 +188,9 @@
     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
     mHasVibrator = false;
     mHasButtonUnderPad = false;
+    mHasSensor = false;
     mMotionRanges.clear();
+    mSensors.clear();
 }
 
 const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
@@ -214,4 +219,28 @@
     mMotionRanges.push_back(range);
 }
 
+void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) {
+    if (mSensors.find(info.type) != mSensors.end()) {
+        ALOGW("Sensor type %s already exists, will be replaced by new sensor added.",
+              NamedEnum::string(info.type).c_str());
+    }
+    mSensors.insert_or_assign(info.type, info);
+}
+
+const std::vector<InputDeviceSensorType> InputDeviceInfo::getSensorTypes() {
+    std::vector<InputDeviceSensorType> types;
+    for (const auto& [type, info] : mSensors) {
+        types.push_back(type);
+    }
+    return types;
+}
+
+const InputDeviceSensorInfo* InputDeviceInfo::getSensorInfo(InputDeviceSensorType type) {
+    auto it = mSensors.find(type);
+    if (it == mSensors.end()) {
+        return nullptr;
+    }
+    return &it->second;
+}
+
 } // namespace android
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index f5432ad..5666de6 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -103,6 +103,48 @@
     }
 }
 
+bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
+    if (mType != other.mType) {
+        return false;
+    }
+    if (mKeys.size() != other.mKeys.size() ||
+        mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
+        mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
+        return false;
+    }
+
+    for (size_t i = 0; i < mKeys.size(); i++) {
+        if (mKeys.keyAt(i) != other.mKeys.keyAt(i)) {
+            return false;
+        }
+        const Key* key = mKeys.valueAt(i);
+        const Key* otherKey = other.mKeys.valueAt(i);
+        if (key->label != otherKey->label || key->number != otherKey->number) {
+            return false;
+        }
+    }
+
+    for (size_t i = 0; i < mKeysByScanCode.size(); i++) {
+        if (mKeysByScanCode.keyAt(i) != other.mKeysByScanCode.keyAt(i)) {
+            return false;
+        }
+        if (mKeysByScanCode.valueAt(i) != other.mKeysByScanCode.valueAt(i)) {
+            return false;
+        }
+    }
+
+    for (size_t i = 0; i < mKeysByUsageCode.size(); i++) {
+        if (mKeysByUsageCode.keyAt(i) != other.mKeysByUsageCode.keyAt(i)) {
+            return false;
+        }
+        if (mKeysByUsageCode.valueAt(i) != other.mKeysByUsageCode.valueAt(i)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
                                                                      Format format) {
     Tokenizer* tokenizer;
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 16ce48a..d36e417 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -20,12 +20,13 @@
 
 #include <android/keycodes.h>
 #include <input/InputEventLabels.h>
-#include <input/Keyboard.h>
 #include <input/KeyLayoutMap.h>
-#include <utils/Log.h>
+#include <input/Keyboard.h>
+#include <input/NamedEnum.h>
 #include <utils/Errors.h>
-#include <utils/Tokenizer.h>
+#include <utils/Log.h>
 #include <utils/Timers.h>
+#include <utils/Tokenizer.h>
 
 // Enables debug output for the parser.
 #define DEBUG_PARSER 0
@@ -41,6 +42,26 @@
 
 static const char* WHITESPACE = " \t\r";
 
+#define SENSOR_ENTRY(type) NamedEnum::string(type), type
+static const std::unordered_map<std::string, InputDeviceSensorType> SENSOR_LIST =
+        {{SENSOR_ENTRY(InputDeviceSensorType::ACCELEROMETER)},
+         {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD)},
+         {SENSOR_ENTRY(InputDeviceSensorType::ORIENTATION)},
+         {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE)},
+         {SENSOR_ENTRY(InputDeviceSensorType::LIGHT)},
+         {SENSOR_ENTRY(InputDeviceSensorType::PRESSURE)},
+         {SENSOR_ENTRY(InputDeviceSensorType::TEMPERATURE)},
+         {SENSOR_ENTRY(InputDeviceSensorType::PROXIMITY)},
+         {SENSOR_ENTRY(InputDeviceSensorType::GRAVITY)},
+         {SENSOR_ENTRY(InputDeviceSensorType::LINEAR_ACCELERATION)},
+         {SENSOR_ENTRY(InputDeviceSensorType::ROTATION_VECTOR)},
+         {SENSOR_ENTRY(InputDeviceSensorType::RELATIVE_HUMIDITY)},
+         {SENSOR_ENTRY(InputDeviceSensorType::AMBIENT_TEMPERATURE)},
+         {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED)},
+         {SENSOR_ENTRY(InputDeviceSensorType::GAME_ROTATION_VECTOR)},
+         {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)},
+         {SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}};
+
 // --- KeyLayoutMap ---
 
 KeyLayoutMap::KeyLayoutMap() {
@@ -127,6 +148,24 @@
     return NO_ERROR;
 }
 
+// Return pair of sensor type and sensor data index, for the input device abs code
+base::Result<std::pair<InputDeviceSensorType, int32_t>> KeyLayoutMap::mapSensor(int32_t absCode) {
+    auto it = mSensorsByAbsCode.find(absCode);
+    if (it == mSensorsByAbsCode.end()) {
+#if DEBUG_MAPPING
+        ALOGD("mapSensor: absCode=%d, ~ Failed.", absCode);
+#endif
+        return Errorf("Can't find abs code {}.", absCode);
+    }
+    const Sensor& sensor = it->second;
+
+#if DEBUG_MAPPING
+    ALOGD("mapSensor: absCode=%d, sensorType=0x%0x, sensorDataIndex=0x%x.", absCode,
+          NamedEnum::string(sensor.sensorType), sensor.sensorDataIndex);
+#endif
+    return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
+}
+
 const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
     if (usageCode) {
         ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
@@ -242,6 +281,10 @@
                 mTokenizer->skipDelimiters(WHITESPACE);
                 status_t status = parseLed();
                 if (status) return status;
+            } else if (keywordToken == "sensor") {
+                mTokenizer->skipDelimiters(WHITESPACE);
+                status_t status = parseSensor();
+                if (status) return status;
             } else {
                 ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
                         keywordToken.string());
@@ -468,4 +511,84 @@
     map.add(code, led);
     return NO_ERROR;
 }
+
+static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
+    auto it = SENSOR_LIST.find(std::string(token));
+    if (it == SENSOR_LIST.end()) {
+        return std::nullopt;
+    }
+    return it->second;
+}
+
+static std::optional<int32_t> getSensorDataIndex(String8 token) {
+    std::string tokenStr(token.string());
+    if (tokenStr == "X") {
+        return 0;
+    } else if (tokenStr == "Y") {
+        return 1;
+    } else if (tokenStr == "Z") {
+        return 2;
+    }
+    return std::nullopt;
+}
+
+// Parse sensor type and data index mapping, as below format
+// sensor <raw abs> <sensor type> <sensor data index>
+// raw abs : the linux abs code of the axis
+// sensor type : string name of InputDeviceSensorType
+// sensor data index : the data index of sensor, out of [X, Y, Z]
+// Examples:
+// sensor 0x00 ACCELEROMETER X
+// sensor 0x01 ACCELEROMETER Y
+// sensor 0x02 ACCELEROMETER Z
+// sensor 0x03 GYROSCOPE X
+// sensor 0x04 GYROSCOPE Y
+// sensor 0x05 GYROSCOPE Z
+status_t KeyLayoutMap::Parser::parseSensor() {
+    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+    char* end;
+    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+    if (*end) {
+        ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(),
+              "abs code", codeToken.string());
+        return BAD_VALUE;
+    }
+
+    std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode;
+    if (map.find(code) != map.end()) {
+        ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(),
+              "abs code", codeToken.string());
+        return BAD_VALUE;
+    }
+
+    mTokenizer->skipDelimiters(WHITESPACE);
+    String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE);
+    std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string());
+    if (!typeOpt) {
+        ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(),
+              sensorTypeToken.string());
+        return BAD_VALUE;
+    }
+    InputDeviceSensorType sensorType = typeOpt.value();
+    mTokenizer->skipDelimiters(WHITESPACE);
+    String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE);
+    std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken);
+    if (!indexOpt) {
+        ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(),
+              sensorDataIndexToken.string());
+        return BAD_VALUE;
+    }
+    int32_t sensorDataIndex = indexOpt.value();
+
+#if DEBUG_PARSER
+    ALOGD("Parsed sensor: abs code=%d, sensorType=%d, sensorDataIndex=%d.", code,
+          NamedEnum::string(sensorType).c_str(), sensorDataIndex);
+#endif
+
+    Sensor sensor;
+    sensor.sensorType = sensorType;
+    sensor.sensorDataIndex = sensorDataIndex;
+    map.emplace(code, sensor);
+    return NO_ERROR;
+}
 };
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index c174ae9..e2cf245 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
-
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
 #include <gtest/gtest.h>
 #include <input/InputDevice.h>
+#include <input/KeyLayoutMap.h>
+#include <input/Keyboard.h>
 
 namespace android {
 
@@ -31,4 +34,52 @@
     ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName());
 }
 
+class InputDeviceKeyMapTest : public testing::Test {
+protected:
+    void loadKeyLayout(const char* name) {
+        std::string path =
+                getInputDeviceConfigurationFilePathByName(name,
+                                                          InputDeviceConfigurationFileType::
+                                                                  KEY_LAYOUT);
+        ASSERT_FALSE(path.empty());
+        base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
+        ASSERT_TRUE(ret) << "Cannot load KeyLayout at " << path;
+        mKeyMap.keyLayoutMap = std::move(*ret);
+        mKeyMap.keyLayoutFile = path;
+    }
+
+    void loadKeyCharacterMap(const char* name) {
+        InputDeviceIdentifier identifier;
+        identifier.name = name;
+        std::string path =
+                getInputDeviceConfigurationFilePathByName(identifier.getCanonicalName(),
+                                                          InputDeviceConfigurationFileType::
+                                                                  KEY_CHARACTER_MAP);
+        ASSERT_FALSE(path.empty()) << "KeyCharacterMap for " << name << " not found";
+        base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+                KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
+        ASSERT_TRUE(ret) << "Cannot load KeyCharacterMap at " << path;
+        mKeyMap.keyCharacterMap = *ret;
+        mKeyMap.keyCharacterMapFile = path;
+    }
+
+    virtual void SetUp() override {
+        loadKeyLayout("Generic");
+        loadKeyCharacterMap("Generic");
+    }
+
+    virtual void TearDown() override {}
+
+    KeyMap mKeyMap;
+};
+
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) {
+    Parcel parcel;
+    mKeyMap.keyCharacterMap->writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel);
+    // Verify the key character map is the same as original
+    ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
+}
+
 } // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index eafb5ab..f5f0400 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -391,6 +391,11 @@
     mListener->notifyMotion(&newArgs);
 }
 
+void InputClassifier::notifySensor(const NotifySensorArgs* args) {
+    // pass through
+    mListener->notifySensor(args);
+}
+
 void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
     // pass through
     mListener->notifySwitch(args);
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 6965940..bf10920 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -229,6 +229,7 @@
     virtual void notifyKey(const NotifyKeyArgs* args) override;
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
+    virtual void notifySensor(const NotifySensorArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 49a813e..4be49b1 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -211,6 +211,41 @@
     listener->notifySwitch(this);
 }
 
+// --- NotifySensorArgs ---
+
+NotifySensorArgs::NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                                   InputDeviceSensorType sensorType,
+                                   InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
+                                   nsecs_t hwTimestamp, std::vector<float> values)
+      : NotifyArgs(id, eventTime),
+        deviceId(deviceId),
+        source(source),
+        sensorType(sensorType),
+        accuracy(accuracy),
+        accuracyChanged(accuracyChanged),
+        hwTimestamp(hwTimestamp),
+        values(std::move(values)) {}
+
+NotifySensorArgs::NotifySensorArgs(const NotifySensorArgs& other)
+      : NotifyArgs(other.id, other.eventTime),
+        deviceId(other.deviceId),
+        source(other.source),
+        sensorType(other.sensorType),
+        accuracy(other.accuracy),
+        accuracyChanged(other.accuracyChanged),
+        hwTimestamp(other.hwTimestamp),
+        values(other.values) {}
+
+bool NotifySensorArgs::operator==(const NotifySensorArgs rhs) const {
+    return id == rhs.id && eventTime == rhs.eventTime && sensorType == rhs.sensorType &&
+            accuracy == rhs.accuracy && accuracyChanged == rhs.accuracyChanged &&
+            hwTimestamp == rhs.hwTimestamp && values == rhs.values;
+}
+
+void NotifySensorArgs::notify(const sp<InputListenerInterface>& listener) const {
+    listener->notifySensor(this);
+}
+
 // --- NotifyDeviceResetArgs ---
 
 NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
@@ -286,6 +321,11 @@
     mArgsQueue.push_back(new NotifySwitchArgs(*args));
 }
 
+void QueuedInputListener::notifySensor(const NotifySensorArgs* args) {
+    traceEvent(__func__, args->id);
+    mArgsQueue.push_back(new NotifySensorArgs(*args));
+}
+
 void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
     traceEvent(__func__, args->id);
     mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 7c572b4..4e55872 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -66,6 +66,13 @@
 
     void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
 
+    void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+                           InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+                           const std::vector<float>& values) override {}
+
+    void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
+                              InputDeviceSensorAccuracy accuracy) override {}
+
     void notifyUntrustedTouch(const std::string& obscuringPackage) override {}
 
     void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index d8a6548..f0976b9 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -239,6 +239,41 @@
     return msg;
 }
 
+// --- SensorEntry ---
+
+SensorEntry::SensorEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                         uint32_t policyFlags, nsecs_t hwTimestamp,
+                         InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy,
+                         bool accuracyChanged, std::vector<float> values)
+      : EventEntry(id, Type::SENSOR, eventTime, policyFlags),
+        deviceId(deviceId),
+        source(source),
+        sensorType(sensorType),
+        accuracy(accuracy),
+        accuracyChanged(accuracyChanged),
+        hwTimestamp(hwTimestamp),
+        values(std::move(values)) {}
+
+SensorEntry::~SensorEntry() {}
+
+std::string SensorEntry::getDescription() const {
+    std::string msg;
+    msg += StringPrintf("SensorEntry(deviceId=%d, source=0x%08x, sensorType=0x%08x, "
+                        "accuracy=0x%08x, hwTimestamp=%" PRId64,
+                        deviceId, source, sensorType, accuracy, hwTimestamp);
+
+    if (!GetBoolProperty("ro.debuggable", false)) {
+        for (size_t i = 0; i < values.size(); i++) {
+            if (i > 0) {
+                msg += ", ";
+            }
+            msg += StringPrintf("(%.3f)", values[i]);
+        }
+    }
+    msg += StringPrintf(", policyFlags=0x%08x", policyFlags);
+    return msg;
+}
+
 // --- DispatchEntry ---
 
 volatile int32_t DispatchEntry::sNextSeqAtomic;
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index fba5514..3a860f0 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -36,26 +36,10 @@
         FOCUS,
         KEY,
         MOTION,
+        SENSOR,
         POINTER_CAPTURE_CHANGED,
     };
 
-    static const char* typeToString(Type type) {
-        switch (type) {
-            case Type::CONFIGURATION_CHANGED:
-                return "CONFIGURATION_CHANGED";
-            case Type::DEVICE_RESET:
-                return "DEVICE_RESET";
-            case Type::FOCUS:
-                return "FOCUS";
-            case Type::KEY:
-                return "KEY";
-            case Type::MOTION:
-                return "MOTION";
-            case Type::POINTER_CAPTURE_CHANGED:
-                return "POINTER_CAPTURE_CHANGED";
-        }
-    }
-
     int32_t id;
     Type type;
     nsecs_t eventTime;
@@ -191,6 +175,25 @@
     virtual ~MotionEntry();
 };
 
+struct SensorEntry : EventEntry {
+    int32_t deviceId;
+    uint32_t source;
+    InputDeviceSensorType sensorType;
+    InputDeviceSensorAccuracy accuracy;
+    bool accuracyChanged;
+    nsecs_t hwTimestamp;
+
+    std::vector<float> values;
+
+    SensorEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                uint32_t policyFlags, nsecs_t hwTimestamp, InputDeviceSensorType sensorType,
+                InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
+                std::vector<float> values);
+    std::string getDescription() const override;
+
+    virtual ~SensorEntry();
+};
+
 // Tracks the progress of dispatching a particular event to a particular connection.
 struct DispatchEntry {
     const uint32_t seq; // unique sequence number, never 0
@@ -257,6 +260,7 @@
     sp<Connection> connection;
     nsecs_t eventTime;
     std::shared_ptr<KeyEntry> keyEntry;
+    std::shared_ptr<SensorEntry> sensorEntry;
     std::shared_ptr<InputApplicationHandle> inputApplicationHandle;
     std::string reason;
     int32_t userActivityEventType;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6c44a54..3af3372 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -47,8 +47,6 @@
 // Log debug messages about hover events.
 #define DEBUG_HOVER 0
 
-#include "InputDispatcher.h"
-
 #include <android-base/chrono_utils.h>
 #include <android-base/stringprintf.h>
 #include <android/os/IInputConstants.h>
@@ -73,6 +71,7 @@
 #include <sstream>
 
 #include "Connection.h"
+#include "InputDispatcher.h"
 
 #define INDENT "  "
 #define INDENT2 "    "
@@ -758,6 +757,23 @@
             done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
             break;
         }
+
+        case EventEntry::Type::SENSOR: {
+            std::shared_ptr<SensorEntry> sensorEntry =
+                    std::static_pointer_cast<SensorEntry>(mPendingEvent);
+            if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
+                dropReason = DropReason::APP_SWITCH;
+            }
+            //  Sensor timestamps use SYSTEM_TIME_BOOTTIME time base, so we can't use
+            // 'currentTime' here, get SYSTEM_TIME_BOOTTIME instead.
+            nsecs_t bootTime = systemTime(SYSTEM_TIME_BOOTTIME);
+            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(bootTime, *sensorEntry)) {
+                dropReason = DropReason::STALE;
+            }
+            dispatchSensorLocked(currentTime, sensorEntry, &dropReason, nextWakeupTime);
+            done = true;
+            break;
+        }
     }
 
     if (done) {
@@ -873,6 +889,7 @@
         }
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::SENSOR:
         case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             // nothing to do
             break;
@@ -883,7 +900,10 @@
 }
 
 void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) {
-    mRecentQueue.push_back(entry);
+    // Do not store sensor event in recent queue to avoid flooding the queue.
+    if (entry->type != EventEntry::Type::SENSOR) {
+        mRecentQueue.push_back(entry);
+    }
     if (mRecentQueue.size() > RECENT_QUEUE_MAX_SIZE) {
         mRecentQueue.pop_front();
     }
@@ -1006,13 +1026,16 @@
             }
             break;
         }
+        case EventEntry::Type::SENSOR: {
+            break;
+        }
         case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             break;
         }
         case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
-            LOG_ALWAYS_FATAL("Should not drop %s events", EventEntry::typeToString(entry.type));
+            LOG_ALWAYS_FATAL("Should not drop %s events", NamedEnum::string(entry.type).c_str());
             break;
         }
     }
@@ -1365,6 +1388,51 @@
 #endif
 }
 
+void InputDispatcher::doNotifySensorLockedInterruptible(CommandEntry* commandEntry) {
+    mLock.unlock();
+
+    const std::shared_ptr<SensorEntry>& entry = commandEntry->sensorEntry;
+    if (entry->accuracyChanged) {
+        mPolicy->notifySensorAccuracy(entry->deviceId, entry->sensorType, entry->accuracy);
+    }
+    mPolicy->notifySensorEvent(entry->deviceId, entry->sensorType, entry->accuracy,
+                               entry->hwTimestamp, entry->values);
+    mLock.lock();
+}
+
+void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, std::shared_ptr<SensorEntry> entry,
+                                           DropReason* dropReason, nsecs_t* nextWakeupTime) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+    ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
+          "source=0x%x, sensorType=%s",
+          entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
+          NamedEnum::string(sensorType).c_str());
+#endif
+    std::unique_ptr<CommandEntry> commandEntry =
+            std::make_unique<CommandEntry>(&InputDispatcher::doNotifySensorLockedInterruptible);
+    commandEntry->sensorEntry = entry;
+    postCommandLocked(std::move(commandEntry));
+}
+
+bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+    ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
+          NamedEnum::string(sensorType).c_str());
+#endif
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+
+        for (auto it = mInboundQueue.begin(); it != mInboundQueue.end(); it++) {
+            std::shared_ptr<EventEntry> entry = *it;
+            if (entry->type == EventEntry::Type::SENSOR) {
+                it = mInboundQueue.erase(it);
+                releaseInboundEventLocked(entry);
+            }
+        }
+    }
+    return true;
+}
+
 bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
                                            DropReason* dropReason, nsecs_t* nextWakeupTime) {
     ATRACE_CALL();
@@ -1553,8 +1621,9 @@
         case EventEntry::Type::POINTER_CAPTURE_CHANGED:
         case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
-        case EventEntry::Type::DEVICE_RESET: {
-            ALOGE("%s events do not have a target display", EventEntry::typeToString(entry.type));
+        case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::SENSOR: {
+            ALOGE("%s events do not have a target display", NamedEnum::string(entry.type).c_str());
             return ADISPLAY_ID_NONE;
         }
     }
@@ -1608,7 +1677,7 @@
     if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) {
         ALOGI("Dropping %s event because there is no focused window or focused application in "
               "display %" PRId32 ".",
-              EventEntry::typeToString(entry.type), displayId);
+              NamedEnum::string(entry.type).c_str(), displayId);
         return InputEventInjectionResult::FAILED;
     }
 
@@ -1633,7 +1702,7 @@
         } else if (currentTime > *mNoFocusedWindowTimeoutTime) {
             // Already raised ANR. Drop the event
             ALOGE("Dropping %s event because there is no focused window",
-                  EventEntry::typeToString(entry.type));
+                  NamedEnum::string(entry.type).c_str());
             return InputEventInjectionResult::FAILED;
         } else {
             // Still waiting for the focused window
@@ -2476,9 +2545,10 @@
         case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::SENSOR:
         case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             LOG_ALWAYS_FATAL("%s events are not user activity",
-                             EventEntry::typeToString(eventEntry.type));
+                             NamedEnum::string(eventEntry.type).c_str());
             break;
         }
     }
@@ -2522,7 +2592,7 @@
     if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
         LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
                             "Entry type %s should not have FLAG_SPLIT",
-                            EventEntry::typeToString(eventEntry->type));
+                            NamedEnum::string(eventEntry->type).c_str());
 
         const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
         if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
@@ -2692,10 +2762,14 @@
         case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             break;
         }
+        case EventEntry::Type::SENSOR: {
+            LOG_ALWAYS_FATAL("SENSOR events should not go to apps via input channel");
+            break;
+        }
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             LOG_ALWAYS_FATAL("%s events should not go to apps",
-                             EventEntry::typeToString(newEntry.type));
+                             NamedEnum::string(newEntry.type).c_str());
             break;
         }
     }
@@ -2913,9 +2987,10 @@
             }
 
             case EventEntry::Type::CONFIGURATION_CHANGED:
-            case EventEntry::Type::DEVICE_RESET: {
+            case EventEntry::Type::DEVICE_RESET:
+            case EventEntry::Type::SENSOR: {
                 LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
-                                 EventEntry::typeToString(eventEntry.type));
+                                 NamedEnum::string(eventEntry.type).c_str());
                 return;
             }
         }
@@ -3209,13 +3284,14 @@
             case EventEntry::Type::FOCUS:
             case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
                 LOG_ALWAYS_FATAL("Canceling %s events is not supported",
-                                 EventEntry::typeToString(cancelationEventEntry->type));
+                                 NamedEnum::string(cancelationEventEntry->type).c_str());
                 break;
             }
             case EventEntry::Type::CONFIGURATION_CHANGED:
-            case EventEntry::Type::DEVICE_RESET: {
+            case EventEntry::Type::DEVICE_RESET:
+            case EventEntry::Type::SENSOR: {
                 LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
-                                 EventEntry::typeToString(cancelationEventEntry->type));
+                                 NamedEnum::string(cancelationEventEntry->type).c_str());
                 break;
             }
         }
@@ -3270,9 +3346,10 @@
             case EventEntry::Type::FOCUS:
             case EventEntry::Type::CONFIGURATION_CHANGED:
             case EventEntry::Type::DEVICE_RESET:
-            case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
+            case EventEntry::Type::POINTER_CAPTURE_CHANGED:
+            case EventEntry::Type::SENSOR: {
                 LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
-                                     EventEntry::typeToString(downEventEntry->type));
+                                 NamedEnum::string(downEventEntry->type).c_str());
                 break;
             }
         }
@@ -3605,6 +3682,34 @@
     }
 }
 
+void InputDispatcher::notifySensor(const NotifySensorArgs* args) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+    ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
+          " sensorType=%s",
+          args->id, args->eventTime, args->deviceId, args->source,
+          NamedEnum::string(args->sensorType).c_str());
+#endif
+
+    bool needWake;
+    { // acquire lock
+        mLock.lock();
+
+        // Just enqueue a new sensor event.
+        std::unique_ptr<SensorEntry> newEntry =
+                std::make_unique<SensorEntry>(args->id, args->eventTime, args->deviceId,
+                                              args->source, 0 /* policyFlags*/, args->hwTimestamp,
+                                              args->sensorType, args->accuracy,
+                                              args->accuracyChanged, args->values);
+
+        needWake = enqueueInboundEventLocked(std::move(newEntry));
+        mLock.unlock();
+    } // release lock
+
+    if (needWake) {
+        mLooper->wake();
+    }
+}
+
 bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) {
     return mInputFilterEnabled;
 }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 5d37645..3004701 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -94,6 +94,7 @@
     virtual void notifyKey(const NotifyKeyArgs* args) override;
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
+    virtual void notifySensor(const NotifySensorArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
     virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
@@ -128,6 +129,7 @@
     virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
     virtual status_t pilferPointers(const sp<IBinder>& token) override;
     virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override;
+    virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override;
 
     std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
 
@@ -392,7 +394,8 @@
             DropReason& dropReason) REQUIRES(mLock);
     void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry,
                              const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
-
+    void dispatchSensorLocked(nsecs_t currentTime, std::shared_ptr<SensorEntry> entry,
+                              DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry);
     void logOutboundMotionDetails(const char* prefix, const MotionEntry& entry);
 
@@ -592,6 +595,7 @@
             REQUIRES(mLock);
     void doNotifyConnectionResponsiveLockedInterruptible(CommandEntry* commandEntry)
             REQUIRES(mLock);
+    void doNotifySensorLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
             REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 1656a21..3bb0bc9 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "input/InputDevice.h"
+
 #include "InputState.h"
 
 #include "InputDispatcher.h"
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 2909d69..6e76c92 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -25,6 +25,7 @@
 #include <android/os/InputEventInjectionResult.h>
 #include <android/os/InputEventInjectionSync.h>
 #include <input/InputApplication.h>
+#include <input/InputDevice.h>
 #include <input/InputTransport.h>
 #include <input/InputWindow.h>
 #include <unordered_map>
@@ -193,6 +194,11 @@
      * InputDispatcher is the source of truth of Pointer Capture.
      */
     virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) = 0;
+    /* Flush input device motion sensor.
+     *
+     * Returns true on success.
+     */
+    virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index c1821ab..d9ec020 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -68,6 +68,11 @@
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
     virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
+    virtual void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+                                   InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+                                   const std::vector<float>& values) = 0;
+    virtual void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
+                                      InputDeviceSensorAccuracy accuracy) = 0;
 
     /* Notifies the system that an untrusted touch occurred. */
     virtual void notifyUntrustedTouch(const std::string& obscuringPackage) = 0;
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 58eb915..11f726d 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include <input/Input.h>
+#include <input/InputDevice.h>
 #include <input/TouchVideoFrame.h>
 #include <utils/RefBase.h>
 
@@ -141,6 +142,30 @@
     virtual void notify(const sp<InputListenerInterface>& listener) const;
 };
 
+/* Describes a sensor event. */
+struct NotifySensorArgs : public NotifyArgs {
+    int32_t deviceId;
+    uint32_t source;
+    InputDeviceSensorType sensorType;
+    InputDeviceSensorAccuracy accuracy;
+    bool accuracyChanged;
+    nsecs_t hwTimestamp;
+    std::vector<float> values;
+
+    inline NotifySensorArgs() {}
+
+    NotifySensorArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                     InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy,
+                     bool accuracyChanged, nsecs_t hwTimestamp, std::vector<float> values);
+
+    NotifySensorArgs(const NotifySensorArgs& other);
+
+    bool operator==(const NotifySensorArgs rhs) const;
+
+    ~NotifySensorArgs() override {}
+
+    void notify(const sp<InputListenerInterface>& listener) const override;
+};
 
 /* Describes a switch event. */
 struct NotifySwitchArgs : public NotifyArgs {
@@ -211,6 +236,7 @@
     virtual void notifyKey(const NotifyKeyArgs* args) = 0;
     virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
     virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
+    virtual void notifySensor(const NotifySensorArgs* args) = 0;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
     virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0;
 };
@@ -231,6 +257,7 @@
     virtual void notifyKey(const NotifyKeyArgs* args) override;
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
+    virtual void notifySensor(const NotifySensorArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 6cce8ec..ea9b483 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -111,6 +111,17 @@
 
     /* Return true if the device can send input events to the specified display. */
     virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
+
+    /* Enable sensor in input reader mapper. */
+    virtual bool enableSensor(int32_t deviceId, InputDeviceSensorType sensorType,
+                              std::chrono::microseconds samplingPeriod,
+                              std::chrono::microseconds maxBatchReportLatency) = 0;
+
+    /* Disable sensor in input reader mapper. */
+    virtual void disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
+
+    /* Flush sensor data in input reader mapper. */
+    virtual void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
 };
 
 // --- InputReaderConfiguration ---
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
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7632814..c819091 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -284,6 +284,12 @@
     void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
 
     void notifyUntrustedTouch(const std::string& obscuringPackage) override {}
+    void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+                           InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+                           const std::vector<float>& values) override {}
+
+    void notifySensorAccuracy(int deviceId, InputDeviceSensorType sensorType,
+                              InputDeviceSensorAccuracy accuracy) override {}
 
     void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
         *outConfig = mConfig;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index c26a389..23f3026 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -22,6 +22,7 @@
 #include <InputReaderFactory.h>
 #include <KeyboardInputMapper.h>
 #include <MultiTouchInputMapper.h>
+#include <SensorInputMapper.h>
 #include <SingleTouchInputMapper.h>
 #include <SwitchInputMapper.h>
 #include <TestInputListener.h>
@@ -364,6 +365,11 @@
         uint32_t flags;
     };
 
+    struct SensorInfo {
+        InputDeviceSensorType sensorType;
+        int32_t sensorDataIndex;
+    };
+
     struct Device {
         InputDeviceIdentifier identifier;
         Flags<InputDeviceClass> classes;
@@ -377,6 +383,8 @@
         KeyedVector<int32_t, KeyInfo> keysByScanCode;
         KeyedVector<int32_t, KeyInfo> keysByUsageCode;
         KeyedVector<int32_t, bool> leds;
+        std::unordered_map<int32_t, SensorInfo> sensorsByAbsCode;
+        BitArray<MSC_MAX> mscBitmask;
         std::vector<VirtualKeyDefinition> virtualKeys;
         bool enabled;
 
@@ -535,6 +543,22 @@
         device->leds.add(led, initialState);
     }
 
+    void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType,
+                       int32_t sensorDataIndex) {
+        Device* device = getDevice(deviceId);
+        SensorInfo info;
+        info.sensorType = sensorType;
+        info.sensorDataIndex = sensorDataIndex;
+        device->sensorsByAbsCode.emplace(absCode, info);
+    }
+
+    void setMscEvent(int32_t deviceId, int32_t mscEvent) {
+        Device* device = getDevice(deviceId);
+        typename BitArray<MSC_MAX>::Buffer buffer;
+        buffer[mscEvent / 32] = 1 << mscEvent % 32;
+        device->mscBitmask.loadFromBuffer(buffer);
+    }
+
     bool getLedState(int32_t deviceId, int32_t led) {
         Device* device = getDevice(deviceId);
         return device->leds.valueFor(led);
@@ -630,6 +654,14 @@
 
     bool hasInputProperty(int32_t, int) const override { return false; }
 
+    bool hasMscEvent(int32_t deviceId, int mscEvent) const override final {
+        Device* device = getDevice(deviceId);
+        if (device) {
+            return mscEvent >= 0 && mscEvent <= MSC_MAX ? device->mscBitmask.test(mscEvent) : false;
+        }
+        return false;
+    }
+
     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 {
         Device* device = getDevice(deviceId);
@@ -669,6 +701,20 @@
 
     status_t mapAxis(int32_t, int32_t, AxisInfo*) const override { return NAME_NOT_FOUND; }
 
+    base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId,
+                                                                      int32_t absCode) {
+        Device* device = getDevice(deviceId);
+        if (!device) {
+            return Errorf("Sensor device not found.");
+        }
+        auto it = device->sensorsByAbsCode.find(absCode);
+        if (it == device->sensorsByAbsCode.end()) {
+            return Errorf("Sensor map not found.");
+        }
+        const SensorInfo& info = it->second;
+        return std::make_pair(info.sensorType, info.sensorDataIndex);
+    }
+
     void setExcludedDevices(const std::vector<std::string>& devices) override {
         mExcludedDevices = devices;
     }
@@ -2574,6 +2620,157 @@
     ASSERT_TRUE(mapper.isVibrating());
 }
 
+// --- SensorInputMapperTest ---
+
+class SensorInputMapperTest : public InputMapperTest {
+protected:
+    static const int32_t ACCEL_RAW_MIN;
+    static const int32_t ACCEL_RAW_MAX;
+    static const int32_t ACCEL_RAW_FUZZ;
+    static const int32_t ACCEL_RAW_FLAT;
+    static const int32_t ACCEL_RAW_RESOLUTION;
+
+    static const int32_t GYRO_RAW_MIN;
+    static const int32_t GYRO_RAW_MAX;
+    static const int32_t GYRO_RAW_FUZZ;
+    static const int32_t GYRO_RAW_FLAT;
+    static const int32_t GYRO_RAW_RESOLUTION;
+
+    static const float GRAVITY_MS2_UNIT;
+    static const float DEGREE_RADIAN_UNIT;
+
+    void prepareAccelAxes();
+    void prepareGyroAxes();
+    void setAccelProperties();
+    void setGyroProperties();
+    void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::SENSOR); }
+};
+
+const int32_t SensorInputMapperTest::ACCEL_RAW_MIN = -32768;
+const int32_t SensorInputMapperTest::ACCEL_RAW_MAX = 32768;
+const int32_t SensorInputMapperTest::ACCEL_RAW_FUZZ = 16;
+const int32_t SensorInputMapperTest::ACCEL_RAW_FLAT = 0;
+const int32_t SensorInputMapperTest::ACCEL_RAW_RESOLUTION = 8192;
+
+const int32_t SensorInputMapperTest::GYRO_RAW_MIN = -2097152;
+const int32_t SensorInputMapperTest::GYRO_RAW_MAX = 2097152;
+const int32_t SensorInputMapperTest::GYRO_RAW_FUZZ = 16;
+const int32_t SensorInputMapperTest::GYRO_RAW_FLAT = 0;
+const int32_t SensorInputMapperTest::GYRO_RAW_RESOLUTION = 1024;
+
+const float SensorInputMapperTest::GRAVITY_MS2_UNIT = 9.80665f;
+const float SensorInputMapperTest::DEGREE_RADIAN_UNIT = 0.0174533f;
+
+void SensorInputMapperTest::prepareAccelAxes() {
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
+                                   ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
+                                   ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Z, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_FUZZ,
+                                   ACCEL_RAW_FLAT, ACCEL_RAW_RESOLUTION);
+}
+
+void SensorInputMapperTest::prepareGyroAxes() {
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RX, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
+                                   GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RY, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
+                                   GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_RZ, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_FUZZ,
+                                   GYRO_RAW_FLAT, GYRO_RAW_RESOLUTION);
+}
+
+void SensorInputMapperTest::setAccelProperties() {
+    mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 0, InputDeviceSensorType::ACCELEROMETER,
+                                 /* sensorDataIndex */ 0);
+    mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 1, InputDeviceSensorType::ACCELEROMETER,
+                                 /* sensorDataIndex */ 1);
+    mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 2, InputDeviceSensorType::ACCELEROMETER,
+                                 /* sensorDataIndex */ 2);
+    mFakeEventHub->setMscEvent(EVENTHUB_ID, MSC_TIMESTAMP);
+    addConfigurationProperty("sensor.accelerometer.reportingMode", "0");
+    addConfigurationProperty("sensor.accelerometer.maxDelay", "100000");
+    addConfigurationProperty("sensor.accelerometer.minDelay", "5000");
+    addConfigurationProperty("sensor.accelerometer.power", "1.5");
+}
+
+void SensorInputMapperTest::setGyroProperties() {
+    mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 3, InputDeviceSensorType::GYROSCOPE,
+                                 /* sensorDataIndex */ 0);
+    mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 4, InputDeviceSensorType::GYROSCOPE,
+                                 /* sensorDataIndex */ 1);
+    mFakeEventHub->addSensorAxis(EVENTHUB_ID, /* absCode */ 5, InputDeviceSensorType::GYROSCOPE,
+                                 /* sensorDataIndex */ 2);
+    mFakeEventHub->setMscEvent(EVENTHUB_ID, MSC_TIMESTAMP);
+    addConfigurationProperty("sensor.gyroscope.reportingMode", "0");
+    addConfigurationProperty("sensor.gyroscope.maxDelay", "100000");
+    addConfigurationProperty("sensor.gyroscope.minDelay", "5000");
+    addConfigurationProperty("sensor.gyroscope.power", "0.8");
+}
+
+TEST_F(SensorInputMapperTest, GetSources) {
+    SensorInputMapper& mapper = addMapperAndConfigure<SensorInputMapper>();
+
+    ASSERT_EQ(static_cast<uint32_t>(AINPUT_SOURCE_SENSOR), mapper.getSources());
+}
+
+TEST_F(SensorInputMapperTest, ProcessAccelerometerSensor) {
+    setAccelProperties();
+    prepareAccelAxes();
+    SensorInputMapper& mapper = addMapperAndConfigure<SensorInputMapper>();
+
+    ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::ACCELEROMETER,
+                                    std::chrono::microseconds(10000),
+                                    std::chrono::microseconds(0)));
+    process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, 20000);
+    process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, -20000);
+    process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Z, 40000);
+    process(mapper, ARBITRARY_TIME, EV_MSC, MSC_TIMESTAMP, 1000);
+    process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    NotifySensorArgs args;
+    std::vector<float> values = {20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT,
+                                 -20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT,
+                                 40000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT};
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySensorWasCalled(&args));
+    ASSERT_EQ(args.source, AINPUT_SOURCE_SENSOR);
+    ASSERT_EQ(args.deviceId, DEVICE_ID);
+    ASSERT_EQ(args.sensorType, InputDeviceSensorType::ACCELEROMETER);
+    ASSERT_EQ(args.accuracy, InputDeviceSensorAccuracy::ACCURACY_HIGH);
+    ASSERT_EQ(args.hwTimestamp, ARBITRARY_TIME);
+    ASSERT_EQ(args.values, values);
+    mapper.flushSensor(InputDeviceSensorType::ACCELEROMETER);
+}
+
+TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) {
+    setGyroProperties();
+    prepareGyroAxes();
+    SensorInputMapper& mapper = addMapperAndConfigure<SensorInputMapper>();
+
+    ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::GYROSCOPE,
+                                    std::chrono::microseconds(10000),
+                                    std::chrono::microseconds(0)));
+    process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RX, 20000);
+    process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RY, -20000);
+    process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RZ, 40000);
+    process(mapper, ARBITRARY_TIME, EV_MSC, MSC_TIMESTAMP, 1000);
+    process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+
+    NotifySensorArgs args;
+    std::vector<float> values = {20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT,
+                                 -20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT,
+                                 40000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT};
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySensorWasCalled(&args));
+    ASSERT_EQ(args.source, AINPUT_SOURCE_SENSOR);
+    ASSERT_EQ(args.deviceId, DEVICE_ID);
+    ASSERT_EQ(args.sensorType, InputDeviceSensorType::GYROSCOPE);
+    ASSERT_EQ(args.accuracy, InputDeviceSensorAccuracy::ACCURACY_HIGH);
+    ASSERT_EQ(args.hwTimestamp, ARBITRARY_TIME);
+    ASSERT_EQ(args.values, values);
+    mapper.flushSensor(InputDeviceSensorType::GYROSCOPE);
+}
+
 // --- KeyboardInputMapperTest ---
 
 class KeyboardInputMapperTest : public InputMapperTest {
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 1050ab8..295c6e3 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -80,6 +80,12 @@
                                            "Expected notifySwitch() to have been called."));
 }
 
+void TestInputListener::assertNotifySensorWasCalled(NotifySensorArgs* outEventArgs) {
+    ASSERT_NO_FATAL_FAILURE(
+            assertCalled<NotifySensorArgs>(outEventArgs,
+                                           "Expected notifySensor() to have been called."));
+}
+
 void TestInputListener::assertNotifyCaptureWasCalled(
         NotifyPointerCaptureChangedArgs* outEventArgs) {
     ASSERT_NO_FATAL_FAILURE(
@@ -155,4 +161,8 @@
     notify<NotifyPointerCaptureChangedArgs>(args);
 }
 
+void TestInputListener::notifySensor(const NotifySensorArgs* args) {
+    notify<NotifySensorArgs>(args);
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 887d4ea..e54350a 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -55,6 +55,7 @@
     void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
 
     void assertNotifyCaptureWasCalled(NotifyPointerCaptureChangedArgs* outEventArgs = nullptr);
+    void assertNotifySensorWasCalled(NotifySensorArgs* outEventArgs = nullptr);
 
 private:
     template <class NotifyArgsType>
@@ -76,6 +77,8 @@
 
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
 
+    virtual void notifySensor(const NotifySensorArgs* args) override;
+
     virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     std::mutex mLock;
@@ -88,6 +91,7 @@
                std::vector<NotifyKeyArgs>,                   //
                std::vector<NotifyMotionArgs>,                //
                std::vector<NotifySwitchArgs>,                //
+               std::vector<NotifySensorArgs>,                //
                std::vector<NotifyPointerCaptureChangedArgs>> //
             mQueues GUARDED_BY(mLock);
 };