Merge "[SurfaceFlinger] Push atoms on janky events"
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index 8b868fb..a61f6bf 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -75,8 +75,7 @@
 
 bool CacheTracker::loadQuotaStats() {
     int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
-    int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
-    if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) {
+    if (IsQuotaSupported(mUuid) && cacheGid != -1) {
         int64_t space;
         if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) {
             cacheUsed += space;
@@ -84,7 +83,7 @@
             return false;
         }
 
-        if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) {
+        if ((space = get_occupied_app_cache_space_external(mUuid, mUserId, mAppId)) != -1) {
             cacheUsed += space;
         } else {
             return false;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 02e5d9b..c9b51b5 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -54,6 +54,7 @@
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
+#include <private/android_projectid_config.h>
 #include <selinux/android.h>
 #include <system/thread_defs.h>
 #include <utils/Trace.h>
@@ -1487,8 +1488,8 @@
 static void collectQuotaStats(const std::string& uuid, int32_t userId,
         int32_t appId, struct stats* stats, struct stats* extStats) {
     int64_t space;
+    uid_t uid = multiuser_get_uid(userId, appId);
     if (stats != nullptr) {
-        uid_t uid = multiuser_get_uid(userId, appId);
         if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
             stats->dataSize += space;
         }
@@ -1509,20 +1510,44 @@
     }
 
     if (extStats != nullptr) {
-        int extGid = multiuser_get_ext_gid(userId, appId);
-        if (extGid != -1) {
-            if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) {
-                extStats->dataSize += space;
+        static const bool supportsSdCardFs = supports_sdcardfs();
+        space = get_occupied_app_space_external(uuid, userId, appId);
+
+        if (space != -1) {
+            extStats->dataSize += space;
+            if (!supportsSdCardFs && stats != nullptr) {
+                // On devices without sdcardfs, if internal and external are on
+                // the same volume, a uid such as u0_a123 is used for
+                // application dirs on both internal and external storage;
+                // therefore, substract that amount from internal to make sure
+                // we don't count it double.
+                stats->dataSize -= space;
             }
         }
 
-        int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
-        if (extCacheGid != -1) {
-            if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) {
-                extStats->dataSize += space;
-                extStats->cacheSize += space;
+        space = get_occupied_app_cache_space_external(uuid, userId, appId);
+        if (space != -1) {
+            extStats->dataSize += space; // cache counts for "data"
+            extStats->cacheSize += space;
+            if (!supportsSdCardFs && stats != nullptr) {
+                // On devices without sdcardfs, if internal and external are on
+                // the same volume, a uid such as u0_a123 is used for both
+                // internal and external storage; therefore, substract that
+                // amount from internal to make sure we don't count it double.
+                stats->dataSize -= space;
             }
         }
+
+        if (!supportsSdCardFs && stats != nullptr) {
+            // On devices without sdcardfs, the UID of OBBs on external storage
+            // matches the regular app UID (eg u0_a123); therefore, to avoid
+            // OBBs being include in stats->dataSize, compute the OBB size for
+            // this app, and substract it from the size reported on internal
+            // storage
+            long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
+            int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+            stats->dataSize -= appObbSize;
+        }
     }
 }
 
@@ -1771,6 +1796,106 @@
     return ok();
 }
 
+struct external_sizes {
+    int64_t audioSize;
+    int64_t videoSize;
+    int64_t imageSize;
+    int64_t totalSize; // excludes OBBs (Android/obb), but includes app data + cache
+    int64_t obbSize;
+};
+
+#define PER_USER_RANGE 100000
+
+static long getProjectIdForUser(int userId, long projectId) {
+    return userId * PER_USER_RANGE + projectId;
+}
+
+static external_sizes getExternalSizesForUserWithQuota(const std::string& uuid, int32_t userId, const std::vector<int32_t>& appIds) {
+    struct external_sizes sizes = {};
+    int64_t space;
+
+    if (supports_sdcardfs()) {
+        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+        if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+            sizes.totalSize = space;
+        }
+
+        gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
+        if ((space = GetOccupiedSpaceForGid(uuid, audioGid)) != -1) {
+            sizes.audioSize = space;
+        }
+
+        gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
+        if ((space = GetOccupiedSpaceForGid(uuid, videoGid)) != -1) {
+            sizes.videoSize = space;
+        }
+
+        gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
+        if ((space = GetOccupiedSpaceForGid(uuid, imageGid)) != -1) {
+            sizes.imageSize = space;
+        }
+
+        if ((space = GetOccupiedSpaceForGid(uuid, AID_MEDIA_OBB)) != -1) {
+            sizes.obbSize = space;
+        }
+    } else {
+        int64_t totalSize = 0;
+        long defaultProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_DEFAULT);
+        if ((space = GetOccupiedSpaceForProjectId(uuid, defaultProjectId)) != -1) {
+            // This is all files that are not audio/video/images, excluding
+            // OBBs and app-private data
+            totalSize += space;
+        }
+
+        long audioProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_AUDIO);
+        if ((space = GetOccupiedSpaceForProjectId(uuid, audioProjectId)) != -1) {
+            sizes.audioSize = space;
+            totalSize += space;
+        }
+
+        long videoProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_VIDEO);
+        if ((space = GetOccupiedSpaceForProjectId(uuid, videoProjectId)) != -1) {
+            sizes.videoSize = space;
+            totalSize += space;
+        }
+
+        long imageProjectId = getProjectIdForUser(userId, PROJECT_ID_EXT_MEDIA_IMAGE);
+        if ((space = GetOccupiedSpaceForProjectId(uuid, imageProjectId)) != -1) {
+            sizes.imageSize = space;
+            totalSize += space;
+        }
+
+        int64_t totalAppDataSize = 0;
+        int64_t totalAppCacheSize = 0;
+        int64_t totalAppObbSize = 0;
+        for (auto appId : appIds) {
+            if (appId >= AID_APP_START) {
+                // App data
+                uid_t uid = multiuser_get_uid(userId, appId);
+                long projectId = uid - AID_APP_START + PROJECT_ID_EXT_DATA_START;
+                totalAppDataSize += GetOccupiedSpaceForProjectId(uuid, projectId);
+
+                // App cache
+                long cacheProjectId = uid - AID_APP_START + PROJECT_ID_EXT_CACHE_START;
+                totalAppCacheSize += GetOccupiedSpaceForProjectId(uuid, cacheProjectId);
+
+                // App OBBs
+                long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
+                totalAppObbSize += GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+            }
+        }
+        // Total size should include app data + cache
+        totalSize += totalAppDataSize;
+        totalSize += totalAppCacheSize;
+        sizes.totalSize = totalSize;
+
+        // Only OBB is separate
+        sizes.obbSize = totalAppObbSize;
+    }
+
+    return sizes;
+}
+
 binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
@@ -1799,14 +1924,6 @@
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        int64_t space;
-
-        ATRACE_BEGIN("obb");
-        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
-            extStats.codeSize += space;
-        }
-        ATRACE_END();
-
         ATRACE_BEGIN("code");
         calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
         ATRACE_END();
@@ -1828,10 +1945,9 @@
         }
 
         ATRACE_BEGIN("external");
-        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
-            extStats.dataSize += space;
-        }
+        auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds);
+        extStats.dataSize += sizes.totalSize;
+        extStats.codeSize += sizes.obbSize;
         ATRACE_END();
 
         if (!uuid) {
@@ -1842,13 +1958,11 @@
                     -1, -1, true);
             ATRACE_END();
         }
-
         ATRACE_BEGIN("quota");
         int64_t dataSize = extStats.dataSize;
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
                 collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
-
 #if MEASURE_DEBUG
                 // Sleep to make sure we don't lose logs
                 usleep(1);
@@ -1944,29 +2058,13 @@
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        int64_t space;
-
         ATRACE_BEGIN("quota");
-        uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
-            totalSize = space;
-        }
-
-        gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
-        if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) {
-            audioSize = space;
-        }
-        gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
-        if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) {
-            videoSize = space;
-        }
-        gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
-        if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) {
-            imageSize = space;
-        }
-        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
-            obbSize = space;
-        }
+        auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds);
+        totalSize = sizes.totalSize;
+        audioSize = sizes.audioSize;
+        videoSize = sizes.videoSize;
+        imageSize = sizes.imageSize;
+        obbSize = sizes.obbSize;
         ATRACE_END();
 
         ATRACE_BEGIN("apps");
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 042d69e..c47df52 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -26,6 +26,7 @@
 #include <sys/xattr.h>
 #include <sys/statvfs.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <android-base/stringprintf.h>
@@ -34,9 +35,11 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
+#include <private/android_projectid_config.h>
 
 #include "dexopt_return_codes.h"
 #include "globals.h"  // extern variables.
+#include "QuotaUtils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "installd"
@@ -1057,6 +1060,51 @@
     return 0;
 }
 
+static const char* kProcFilesystems = "/proc/filesystems";
+bool supports_sdcardfs() {
+    std::string supported;
+    if (!android::base::ReadFileToString(kProcFilesystems, &supported)) {
+        PLOG(ERROR) << "Failed to read supported filesystems";
+        return false;
+    }
+    return supported.find("sdcardfs\n") != std::string::npos;
+}
+
+int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId) {
+    static const bool supportsSdcardFs = supports_sdcardfs();
+
+    if (supportsSdcardFs) {
+        int extGid = multiuser_get_ext_gid(userId, appId);
+
+        if (extGid == -1) {
+            return -1;
+        }
+
+        return GetOccupiedSpaceForGid(uuid, extGid);
+    } else {
+        uid_t uid = multiuser_get_uid(userId, appId);
+        long projectId = uid - AID_APP_START + PROJECT_ID_EXT_DATA_START;
+        return GetOccupiedSpaceForProjectId(uuid, projectId);
+    }
+}
+int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId) {
+    static const bool supportsSdcardFs = supports_sdcardfs();
+
+    if (supportsSdcardFs) {
+        int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
+
+        if (extCacheGid == -1) {
+            return -1;
+        }
+
+        return GetOccupiedSpaceForGid(uuid, extCacheGid);
+    } else {
+        uid_t uid = multiuser_get_uid(userId, appId);
+        long projectId = uid - AID_APP_START + PROJECT_ID_EXT_CACHE_START;
+        return GetOccupiedSpaceForProjectId(uuid, projectId);
+    }
+}
+
 // Collect all non empty profiles from the given directory and puts then into profile_paths.
 // The profiles are identified based on PROFILE_EXT extension.
 // If a subdirectory or profile file cannot be opened the method logs a warning and moves on.
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 01126c0..549fc6c 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -153,6 +153,10 @@
 int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
         uid_t uid, gid_t gid);
 
+bool supports_sdcardfs();
+int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId);
+int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId);
+
 // Collect all non empty profiles from the global profile directory and
 // put then into profile_paths. The profiles are identified based on PROFILE_EXT extension.
 // If a subdirectory or profile file cannot be opened the method logs a warning and moves on.
diff --git a/include/android/CoolingDevice.h b/include/android/CoolingDevice.h
new file mode 100644
index 0000000..2f366be
--- /dev/null
+++ b/include/android/CoolingDevice.h
@@ -0,0 +1,49 @@
+/*
+ * 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 ANDROID_OS_COOLINGDEVICE_H
+#define ANDROID_OS_COOLINGDEVICE_H
+
+#include <binder/Parcelable.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace os {
+
+/**
+ * CoolingDevice is a structure to encapsulate cooling device status.
+ */
+struct CoolingDevice : public android::Parcelable {
+    /** Current throttle state of the cooling device.  */
+    float mValue;
+    /** A cooling device type from ThermalHAL */
+    uint32_t mType;
+    /** Name of this cooling device */
+    String16 mName;
+
+    CoolingDevice()
+        : mValue(0.0f),
+          mType(0),
+          mName("") {
+    }
+    virtual status_t readFromParcel(const android::Parcel* parcel) override;
+    virtual status_t writeToParcel(android::Parcel* parcel) const override;
+};
+
+} // namespace os
+} // namespace android
+
+#endif /* ANDROID_OS_COOLINGDEVICE_H */
diff --git a/include/android/Temperature.h b/include/android/Temperature.h
new file mode 100644
index 0000000..2e68ec4
--- /dev/null
+++ b/include/android/Temperature.h
@@ -0,0 +1,53 @@
+/*
+ * 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 ANDROID_OS_TEMPERATURE_H
+#define ANDROID_OS_TEMPERATURE_H
+
+#include <binder/Parcelable.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace os {
+
+/**
+ * Temperature is a structure to encapsulate temperature status.
+ */
+struct Temperature : public android::Parcelable {
+    /** Temperature value */
+    float mValue;
+    /** A Temperature type from ThermalHAL */
+    int32_t mType;
+    /** Name of this Temperature */
+    String16 mName;
+    /** The level of the sensor is currently in throttling */
+    int32_t mStatus;
+
+    Temperature()
+        : mValue(0.0f),
+          mType(0),
+          mName(""),
+          mStatus(0) {
+    }
+
+    virtual status_t readFromParcel(const android::Parcel* parcel) override;
+    virtual status_t writeToParcel(android::Parcel* parcel) const override;
+};
+
+} // namespace os
+} // namespace android
+
+#endif /* ANDROID_OS_TEMPERATURE_H */
diff --git a/include/android/thermal.h b/include/android/thermal.h
new file mode 100644
index 0000000..0f4b4d9
--- /dev/null
+++ b/include/android/thermal.h
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup Thermal
+ * @{
+ */
+
+/**
+ * @file thermal.h
+ */
+
+#ifndef _ANDROID_THERMAL_H
+#define _ANDROID_THERMAL_H
+
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Structures and functions to access thermal status and register/unregister
+ * thermal status listener in native code.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(30) /* Introduced in API level 30 */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ANDROID_API__ >= 30
+
+enum AThermalStatus {
+    /** Error in thermal status. */
+    ATHERMAL_STATUS_ERROR = -1,
+    /** Not under throttling. */
+    ATHERMAL_STATUS_NONE = 0,
+    /** Light throttling where UX is not impacted. */
+    ATHERMAL_STATUS_LIGHT = 1,
+    /** Moderate throttling where UX is not largely impacted. */
+    ATHERMAL_STATUS_MODERATE = 2,
+    /** Severe throttling where UX is largely impacted. */
+    ATHERMAL_STATUS_SEVERE = 3,
+    /** Platform has done everything to reduce power. */
+    ATHERMAL_STATUS_CRITICAL = 4,
+    /**
+     * Key components in platform are shutting down due to thermal condition.
+     * Device functionalities will be limited.
+     */
+    ATHERMAL_STATUS_EMERGENCY = 5,
+    /** Need shutdown immediately. */
+    ATHERMAL_STATUS_SHUTDOWN = 6,
+};
+
+/**
+ * An opaque type representing a handle to a thermal manager.
+ * An instance of thermal manager must be acquired prior to
+ * using thermal status APIs and must be released after use.
+ *
+ * <p>To use:<ul>
+ *    <li>Create a new thermal manager instance by calling the
+ *        {@link AThermal_acquireManager} function.</li>
+ *    <li>Get current thermal status with
+ *        {@link AThermal_getCurrentThermalStatus}.</li>
+ *    <li>Register a thermal status listener with
+ *        {@link AThermal_registerThermalStatusListener}.</li>
+ *    <li>Unregister a thermal status listener with
+ *        {@link AThermal_unregisterThermalStatusListener}.</li>
+ *    <li>Release the thermal manager instance with
+ *        {@link AThermal_releaseManager}.</li></ul></p>
+ *
+ */
+typedef struct AThermalManager AThermalManager;
+
+/**
+ * Prototype of the function that is called when thermal status changes.
+ * It's passed the updated thermal status as parameter, as well as the
+ * pointer provided by the client that registered a callback.
+ */
+typedef int (*AThermal_StatusCallback)(void *data, AThermalStatus status);
+
+/**
+  * Acquire an instance of the thermal manager. This must be freed using
+  * {@link AThermal_releaseManager}.
+  *
+  * @return manager instance on success, nullptr on failure.
+ */
+AThermalManager* AThermal_acquireManager();
+
+/**
+ * Release the thermal manager pointer acquired via
+ * {@link AThermal_acquireManager}.
+ *
+ * @param manager The manager to be released.
+ *
+ */
+void AThermal_releaseManager(AThermalManager *manager);
+
+/**
+  * Gets the current thermal status.
+  *
+  * @param manager The manager instance to use to query the thermal status.
+  * Acquired via {@link AThermal_acquireManager}.
+  *
+  * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
+*/
+AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager);
+
+/**
+ * Register the thermal status listener for thermal status change.
+ *
+ * @param manager The manager instance to use to register.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called when thermal status updated.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ *         EINVAL if the listener and data pointer were previously added and not removed.
+ *         EPERM if the required permission is not held.
+ *         EPIPE if communication with the system service has failed.
+ */
+int AThermal_registerThermalStatusListener(AThermalManager *manager,
+        AThermal_StatusCallback callback, void *data);
+
+/**
+ * Unregister the thermal status listener previously resgistered.
+ *
+ * @param manager The manager instance to use to unregister.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param callback The callback function to be called when thermal status updated.
+ * @param data The data pointer to be passed when callback is called.
+ *
+ * @return 0 on success
+ *         EINVAL if the listener and data pointer were not previously added.
+ *         EPERM if the required permission is not held.
+ *         EPIPE if communication with the system service has failed.
+ */
+int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
+        AThermal_StatusCallback callback, void *data);
+
+
+#endif  //  __ANDROID_API__ >= 30
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _ANDROID_THERMAL_H
+
+/** @} */
diff --git a/include/input/Input.h b/include/input/Input.h
index 14a7288..9e47318 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -266,6 +266,38 @@
 const char* motionClassificationToString(MotionClassification classification);
 
 /**
+ * Generator of unique numbers used to identify input events.
+ *
+ * Layout of ID:
+ *     |--------------------------|---------------------------|
+ *     |   2 bits for source      | 30 bits for random number |
+ *     |--------------------------|---------------------------|
+ */
+class IdGenerator {
+private:
+    static constexpr uint32_t SOURCE_SHIFT = 30;
+
+public:
+    // Used to divide integer space to ensure no conflict among these sources./
+    enum class Source : int32_t {
+        INPUT_READER = 0x0 << SOURCE_SHIFT,
+        INPUT_DISPATCHER = 0x1 << SOURCE_SHIFT,
+        OTHER = 0x3 << SOURCE_SHIFT, // E.g. app injected events
+    };
+    IdGenerator(Source source);
+
+    int32_t nextId() const;
+
+    // Extract source from given id.
+    static inline Source getSource(int32_t id) { return static_cast<Source>(SOURCE_MASK & id); }
+
+private:
+    const Source mSource;
+
+    static constexpr int32_t SOURCE_MASK = 0x3 << SOURCE_SHIFT;
+};
+
+/**
  * Invalid value for cursor position. Used for non-mouse events, tests and injected events. Don't
  * use it for direct comparison with any other value, because NaN isn't equal to itself according to
  * IEEE 754. Use isnan() instead to check if a cursor position is valid.
@@ -365,6 +397,8 @@
 
     virtual int32_t getType() const = 0;
 
+    inline int32_t getId() const { return mId; }
+
     inline int32_t getDeviceId() const { return mDeviceId; }
 
     inline uint32_t getSource() const { return mSource; }
@@ -377,11 +411,15 @@
 
     inline std::array<uint8_t, 32> getHmac() const { return mHmac; }
 
+    static int32_t nextId();
+
 protected:
-    void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
+    void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                     std::array<uint8_t, 32> hmac);
+
     void initialize(const InputEvent& from);
 
+    int32_t mId;
     int32_t mDeviceId;
     uint32_t mSource;
     int32_t mDisplayId;
@@ -418,7 +456,7 @@
     static const char* getLabel(int32_t keyCode);
     static int32_t getKeyCodeFromLabel(const char* label);
 
-    void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
+    void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                     std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode,
                     int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime,
                     nsecs_t eventTime);
@@ -642,7 +680,7 @@
 
     ssize_t findPointerIndex(int32_t pointerId) const;
 
-    void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
+    void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                     std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
                     int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
                     MotionClassification classification, float xScale, float yScale, float xOffset,
@@ -722,7 +760,7 @@
 
     inline bool getInTouchMode() const { return mInTouchMode; }
 
-    void initialize(bool hasFocus, bool inTouchMode);
+    void initialize(int32_t id, bool hasFocus, bool inTouchMode);
 
     void initialize(const FocusEvent& from);
 
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 06fd3bb..8ca178c 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -82,7 +82,7 @@
     union Body {
         struct Key {
             uint32_t seq;
-            uint32_t empty1;
+            int32_t eventId;
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
@@ -102,7 +102,7 @@
 
         struct Motion {
             uint32_t seq;
-            uint32_t empty1;
+            int32_t eventId;
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
@@ -159,6 +159,8 @@
 
         struct Focus {
             uint32_t seq;
+            int32_t eventId;
+            uint32_t empty1;
             // The following two fields take up 4 bytes total
             uint16_t hasFocus;    // actually a bool
             uint16_t inTouchMode; // actually a bool, but we must maintain 8-byte alignment
@@ -276,9 +278,9 @@
      * Returns BAD_VALUE if seq is 0.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId,
-                             std::array<uint8_t, 32> hmac, int32_t action, int32_t flags,
-                             int32_t keyCode, int32_t scanCode, int32_t metaState,
+    status_t publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source,
+                             int32_t displayId, std::array<uint8_t, 32> hmac, int32_t action,
+                             int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
                              int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime);
 
     /* Publishes a motion event to the input channel.
@@ -289,14 +291,15 @@
      * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId,
-                                std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
-                                int32_t flags, int32_t edgeFlags, int32_t metaState,
-                                int32_t buttonState, MotionClassification classification,
-                                float xScale, float yScale, float xOffset, float yOffset,
-                                float xPrecision, float yPrecision, float xCursorPosition,
-                                float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
-                                uint32_t pointerCount, const PointerProperties* pointerProperties,
+    status_t publishMotionEvent(uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source,
+                                int32_t displayId, std::array<uint8_t, 32> hmac, int32_t action,
+                                int32_t actionButton, int32_t flags, int32_t edgeFlags,
+                                int32_t metaState, int32_t buttonState,
+                                MotionClassification classification, float xScale, float yScale,
+                                float xOffset, float yOffset, float xPrecision, float yPrecision,
+                                float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+                                nsecs_t eventTime, uint32_t pointerCount,
+                                const PointerProperties* pointerProperties,
                                 const PointerCoords* pointerCoords);
 
     /* Publishes a focus event to the input channel.
@@ -306,7 +309,7 @@
      * Returns DEAD_OBJECT if the channel's peer has been closed.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t publishFocusEvent(uint32_t seq, bool hasFocus, bool inTouchMode);
+    status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
 
     /* Receives the finished signal from the consumer in reply to the original dispatch signal.
      * If a signal was received, returns the message sequence number,
diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h
index 3268b45..9bac242 100644
--- a/include/powermanager/PowerManager.h
+++ b/include/powermanager/PowerManager.h
@@ -33,6 +33,17 @@
     USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_ACCESSIBILITY, // Last valid event code.
 };
 
+/** Keep in sync with android.os.temprature and hardware/interfaces/thermal/2.0/types.hal */
+enum class ThermalStatus : uint32_t {
+    THERMAL_STATUS_NONE = 0,
+    THERMAL_STATUS_LIGHT = 1,
+    THERMAL_STATUS_MODERATE = 2,
+    THERMAL_STATUS_SEVERE = 3,
+    THERMAL_STATUS_CRITICAL = 4,
+    THERMAL_STATUS_EMERGENCY = 5,
+    THERMAL_STATUS_SHUTDOWN = 6,
+};
+
 }; // namespace android
 
 #endif // ANDROID_POWERMANAGER_H
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 8ac044c..8883c04 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -27,7 +27,7 @@
 
     version_script: "libadbd_auth.map.txt",
     stubs: {
-        versions: ["1"],
+        versions: ["30"],
         symbol_file: "libadbd_auth.map.txt",
     },
 
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index a9c2311..5a0d3f6 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -43,6 +43,8 @@
 
 using android::base::unique_fd;
 
+static constexpr uint32_t kAuthVersion = 1;
+
 struct AdbdAuthPacketAuthenticated {
     std::string public_key;
 };
@@ -55,8 +57,21 @@
     std::string public_key;
 };
 
-using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected,
-                                    AdbdAuthPacketRequestAuthorization>;
+struct AdbdPacketTlsDeviceConnected {
+    uint8_t transport_type;
+    std::string public_key;
+};
+
+struct AdbdPacketTlsDeviceDisconnected {
+    uint8_t transport_type;
+    std::string public_key;
+};
+
+using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated,
+                                    AdbdAuthPacketDisconnected,
+                                    AdbdAuthPacketRequestAuthorization,
+                                    AdbdPacketTlsDeviceConnected,
+                                    AdbdPacketTlsDeviceDisconnected>;
 
 struct AdbdAuthContext {
     static constexpr uint64_t kEpollConstSocket = 0;
@@ -65,6 +80,7 @@
 
 public:
     explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
+        InitFrameworkHandlers();
         epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
         if (epoll_fd_ == -1) {
             PLOG(FATAL) << "failed to create epoll fd";
@@ -163,34 +179,56 @@
         }
     }
 
-    void HandlePacket(std::string_view packet) REQUIRES(mutex_) {
+    void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
         LOG(INFO) << "received packet: " << packet;
 
-        if (packet.length() < 2) {
-          LOG(ERROR) << "received packet of invalid length";
-          ReplaceFrameworkFd(unique_fd());
+        if (packet.size() < 2) {
+            LOG(ERROR) << "received packet of invalid length";
+            std::lock_guard<std::mutex> lock(mutex_);
+            ReplaceFrameworkFd(unique_fd());
         }
 
-        if (packet[0] == 'O' && packet[1] == 'K') {
-          CHECK(this->dispatched_prompt_.has_value());
-          auto& [id, key, arg] = *this->dispatched_prompt_;
-          keys_.emplace(id, std::move(key));
-
-          this->callbacks_.key_authorized(arg, id);
-          this->dispatched_prompt_ = std::nullopt;
-
-          // We need to dispatch pending prompts here upon success as well,
-          // since we might have multiple queued prompts.
-          DispatchPendingPrompt();
-        } else if (packet[0] == 'N' && packet[1] == 'O') {
-          CHECK_EQ(2UL, packet.length());
-          // TODO: Do we want a callback if the key is denied?
-          this->dispatched_prompt_ = std::nullopt;
-          DispatchPendingPrompt();
-        } else {
-          LOG(ERROR) << "unhandled packet: " << packet;
-          ReplaceFrameworkFd(unique_fd());
+        bool handled_packet = false;
+        for (size_t i = 0; i < framework_handlers_.size(); ++i) {
+            if (android::base::ConsumePrefix(&packet, framework_handlers_[i].code)) {
+                framework_handlers_[i].cb(packet);
+                handled_packet = true;
+                break;
+            }
         }
+        if (!handled_packet) {
+            LOG(ERROR) << "unhandled packet: " << packet;
+            std::lock_guard<std::mutex> lock(mutex_);
+            ReplaceFrameworkFd(unique_fd());
+        }
+    }
+
+    void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        CHECK(buf.empty());
+        CHECK(dispatched_prompt_.has_value());
+        auto& [id, key, arg] = *dispatched_prompt_;
+        keys_.emplace(id, std::move(key));
+
+        callbacks_.key_authorized(arg, id);
+        dispatched_prompt_ = std::nullopt;
+
+        // We need to dispatch pending prompts here upon success as well,
+        // since we might have multiple queued prompts.
+        DispatchPendingPrompt();
+    }
+
+    void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        CHECK(buf.empty());
+        // TODO: Do we want a callback if the key is denied?
+        dispatched_prompt_ = std::nullopt;
+        DispatchPendingPrompt();
+    }
+
+    void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
+        CHECK(!buf.empty());
+        callbacks_.key_removed(buf.data(), buf.size());
     }
 
     bool SendPacket() REQUIRES(mutex_) {
@@ -201,7 +239,8 @@
         CHECK_NE(-1, framework_fd_.get());
 
         auto& packet = output_queue_.front();
-        struct iovec iovs[2];
+        struct iovec iovs[3];
+        int iovcnt = 2;
         if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) {
             iovs[0].iov_base = const_cast<char*>("CK");
             iovs[0].iov_len = 2;
@@ -217,13 +256,29 @@
             iovs[0].iov_len = 2;
             iovs[1].iov_base = p->public_key.data();
             iovs[1].iov_len = p->public_key.size();
+        } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) {
+            iovcnt = 3;
+            iovs[0].iov_base = const_cast<char*>("WE");
+            iovs[0].iov_len = 2;
+            iovs[1].iov_base = &p->transport_type;
+            iovs[1].iov_len = 1;
+            iovs[2].iov_base = p->public_key.data();
+            iovs[2].iov_len = p->public_key.size();
+        } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) {
+            iovcnt = 3;
+            iovs[0].iov_base = const_cast<char*>("WF");
+            iovs[0].iov_len = 2;
+            iovs[1].iov_base = &p->transport_type;
+            iovs[1].iov_len = 1;
+            iovs[2].iov_base = p->public_key.data();
+            iovs[2].iov_len = p->public_key.size();
         } else {
             LOG(FATAL) << "unhandled packet type?";
         }
 
         output_queue_.pop_front();
 
-        ssize_t rc = writev(framework_fd_.get(), iovs, 2);
+        ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "failed to write to framework fd";
             ReplaceFrameworkFd(unique_fd());
@@ -308,7 +363,6 @@
                                 std::lock_guard<std::mutex> lock(mutex_);
                                 ReplaceFrameworkFd(unique_fd());
                             } else {
-                                std::lock_guard<std::mutex> lock(mutex_);
                                 HandlePacket(std::string_view(buf, rc));
                             }
                         }
@@ -329,7 +383,7 @@
     }
 
     static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
-    void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) {
+    void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
         for (const auto& path : key_paths) {
             if (access(path, R_OK) == 0) {
                 LOG(INFO) << "Loading keys from " << path;
@@ -339,7 +393,7 @@
                     continue;
                 }
                 for (const auto& line : android::base::Split(content, "\n")) {
-                    if (!callback(line.data(), line.size(), arg)) {
+                    if (!callback(opaque, line.data(), line.size())) {
                         return;
                     }
                 }
@@ -361,7 +415,7 @@
         std::lock_guard<std::mutex> lock(mutex_);
         keys_.emplace(id, public_key);
         output_queue_.emplace_back(
-                AdbdAuthPacketDisconnected{.public_key = std::string(public_key)});
+                AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)});
         return id;
     }
 
@@ -376,6 +430,32 @@
         keys_.erase(it);
     }
 
+    uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
+                                      std::string_view public_key) EXCLUDES(mutex_) {
+        uint64_t id = NextId();
+        std::lock_guard<std::mutex> lock(mutex_);
+        keys_.emplace(id, public_key);
+        output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{
+                .transport_type = static_cast<uint8_t>(type),
+                .public_key = std::string(public_key)});
+        Interrupt();
+        return id;
+    }
+
+    void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) {
+        std::lock_guard<std::mutex> lock(mutex_);
+        auto it = keys_.find(id);
+        if (it == keys_.end()) {
+            LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping";
+            return;
+        }
+        output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
+                .transport_type = static_cast<uint8_t>(type),
+                .public_key = std::move(it->second)});
+        keys_.erase(it);
+        Interrupt();
+    }
+
     // Interrupt the worker thread to do some work.
     void Interrupt() {
         uint64_t value = 1;
@@ -387,6 +467,24 @@
         }
     }
 
+    void InitFrameworkHandlers() {
+        // Framework wants to disconnect from a secured wifi device
+        framework_handlers_.emplace_back(
+                FrameworkPktHandler{
+                    .code = "DD",
+                    .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)});
+        // Framework allows USB debugging for the device
+        framework_handlers_.emplace_back(
+                FrameworkPktHandler{
+                    .code = "OK",
+                    .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)});
+        // Framework denies USB debugging for the device
+        framework_handlers_.emplace_back(
+                FrameworkPktHandler{
+                    .code = "NO",
+                    .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)});
+    }
+
     unique_fd epoll_fd_;
     unique_fd event_fd_;
     unique_fd sock_fd_;
@@ -400,19 +498,27 @@
 
     // We keep two separate queues: one to handle backpressure from the socket (output_queue_)
     // and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
-    std::deque<AdbdAuthPacket> output_queue_;
+    std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_);
 
     std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
     std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
+
+    // This is a list of commands that the framework could send to us.
+    using FrameworkHandlerCb = std::function<void(std::string_view)>;
+    struct FrameworkPktHandler {
+        const char* code;
+        FrameworkHandlerCb cb;
+    };
+    std::vector<FrameworkPktHandler> framework_handlers_;
 };
 
 AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
-    if (callbacks->version != 1) {
+    if (callbacks->version == 1) {
+        return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
+    } else {
       LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version;
       return nullptr;
     }
-
-    return new AdbdAuthContext(&callbacks->callbacks.v1);
 }
 
 void adbd_auth_delete(AdbdAuthContext* ctx) {
@@ -424,9 +530,9 @@
 }
 
 void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
-                               bool (*callback)(const char* public_key, size_t len, void* arg),
-                               void* arg) {
-    ctx->IteratePublicKeys(callback, arg);
+                               bool (*callback)(void* opaque, const char* public_key, size_t len),
+                               void* opaque) {
+    ctx->IteratePublicKeys(callback, opaque);
 }
 
 uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
@@ -438,10 +544,28 @@
 }
 
 void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
-                               void* arg) {
-    ctx->PromptUser(std::string_view(public_key, len), arg);
+                           void* opaque) {
+    ctx->PromptUser(std::string_view(public_key, len), opaque);
 }
 
-bool adbd_auth_supports_feature(AdbdAuthFeature) {
+uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
+                                        AdbTransportType type,
+                                        const char* public_key,
+                                        size_t len) {
+    return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len));
+}
+
+void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
+                                       AdbTransportType type,
+                                       uint64_t id) {
+    ctx->NotifyTlsDeviceDisconnected(type, id);
+}
+
+uint32_t adbd_auth_get_max_version() {
+    return kAuthVersion;
+}
+
+bool adbd_auth_supports_feature(AdbdAuthFeature f) {
+    UNUSED(f);
     return false;
 }
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
index b7c1cb8..6ee3166 100644
--- a/libs/adbd_auth/include/adbd_auth.h
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -18,48 +18,159 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <sys/cdefs.h>
 #include <sys/types.h>
 
-extern "C" {
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
 
-struct AdbdAuthCallbacksV1 {
-    // Callback for a successful user authorization.
-    void (*key_authorized)(void* arg, uint64_t id);
+__BEGIN_DECLS
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
+
+// The transport type of the device connection.
+enum AdbTransportType : int32_t {
+    kAdbTransportTypeUsb = 0,
+    kAdbTransportTypeWifi,
 };
+static_assert(sizeof(AdbTransportType) == sizeof(int32_t), "Unexpected AdbTransportType size");
 
 struct AdbdAuthCallbacks {
     uint32_t version;
-    union {
-        AdbdAuthCallbacksV1 v1;
-    } callbacks;
+};
+
+struct AdbdAuthCallbacksV1 : AdbdAuthCallbacks {
+    // Callback for a successful user authorization.
+    void (*key_authorized)(void* opaque, uint64_t id);
+    // The framework removed the key from the keystore. This callback notifies
+    // adbd so it can take the appropriate actions (e.g. disconnect all devices
+    // using that key).
+    void (*key_removed)(const char* public_key, size_t length);
 };
 
 struct AdbdAuthContext;
+typedef struct AdbdAuthContext AdbdAuthContext;
 
-AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks);
-void adbd_auth_delete(AdbdAuthContext* ctx);
+/**
+ * Creates a new AdbdAuthContext.
+ *
+ * @param callbacks a set of user-provided callbacks used internally (see
+ * #AdbdAuthCallbacksV1
+ * @return a new AdbdAuthContext instance. Caller is responsible for destroying
+ * the context with #adbd_auth_delete.
+ */
+AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) __INTRODUCED_IN(30);
 
-void adbd_auth_run(AdbdAuthContext* ctx);
+/**
+ * Destroys the AdbdAuthContext.
+ *
+ * @param ctx the AdbdAuthContext to destroy.
+ */
+void adbd_auth_delete(AdbdAuthContext* ctx) __INTRODUCED_IN(30);
 
-// Iterate through the list of authorized public keys.
-// Return false from the callback to stop iteration.
+/**
+ * Starts the AdbdAuthContext.
+ *
+ * The caller may want to run this on a different thread, as this
+ * runs indefinitely.
+ *
+ * @param ctx the AdbdAuthContext
+ */
+void adbd_auth_run(AdbdAuthContext* ctx) __INTRODUCED_IN(30);
+
+/**
+ * Iterate through the list of authorized public keys.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param callback a callback which will get called for every known adb public
+ * key in its keystore. To stop iteration of the keys, return false in the
+ * callback. Otherwise, return true to continue the iteration.
+ * @param opaque an opaque userdata argument
+ */
 void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
-                               bool (*callback)(const char* public_key, size_t len, void* arg),
-                               void* arg);
+                               bool (*callback)(void* opaque, const char* public_key, size_t len),
+                               void* opaque) __INTRODUCED_IN(30);
 
-// Let system_server know that a key has been successfully used for authentication.
-uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len);
+/**
+ * Let system_server know that a key has been successfully used for authentication.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA key that was authorized using the AUTH protocol
+ * @param len the length of the public_key argument
+ * @return an id corresponding to the new connection
+ */
+uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx,
+                               const char* public_key,
+                               size_t len) __INTRODUCED_IN(30);
 
-// Let system_server know that a connection has been closed.
-void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id);
+/**
+ * Let system_server know that an AUTH connection has been closed.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param id the id of the disconnected device
+ */
+void adbd_auth_notify_disconnect(AdbdAuthContext* ctx,
+                                 uint64_t id) __INTRODUCED_IN(30);
 
-// Prompt the user to authorize a public key.
-// When this happens, a callback will be run on the auth thread with the result.
-void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg);
+/**
+ * Prompt the user to authorize a public key.
+ *
+ * When this happens, a callback will be run on the auth thread with the result.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA public key to prompt user with
+ * @param len the length of the public_key argument
+ * @param arg an opaque userdata argument
+ */
+void adbd_auth_prompt_user(AdbdAuthContext* ctx,
+                           const char* public_key,
+                           size_t len, void* opaque) __INTRODUCED_IN(30);
 
-enum AdbdAuthFeature {
+/**
+ * Let system_server know that a TLS device has connected.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param type the transport type of the connection (see #AdbTransportType)
+ * @param public_key the RSA public key used to establish the connection
+ * @param len the length of the public_key argument
+ * @return an id corresponding to the new connection
+ */
+uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
+                                        AdbTransportType type,
+                                        const char* public_key,
+                                        size_t len) __INTRODUCED_IN(30);
+
+/**
+ * Let system_server know that a TLS device has disconnected.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param type the transport type of the connection (see #AdbTransportType)
+ * @param the id of the disconnected device (see #adbd_tls_device_connected)
+ */
+void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
+                                       AdbTransportType type,
+                                       uint64_t id) __INTRODUCED_IN(30);
+
+/**
+ * Returns the max #AdbdAuthCallbacks version.
+ *
+ * The version starts at 1, with version 1 corresponding to the
+ * #AdbdAuthCallbacksV1 struct.
+ *
+ * @return the max #AdbdAuthCallbacks version.
+ */
+uint32_t adbd_auth_get_max_version(void) __INTRODUCED_IN(30);
+
+enum AdbdAuthFeature : int32_t {
 };
 
-bool adbd_auth_supports_feature(AdbdAuthFeature f);
+/**
+ * Checks if a feature is supported by the framework. See #AdbdAuthFeature.
+ *
+ * @param feature the feature to check for support
+ * @return true if the feature is supported
+ */
+bool adbd_auth_supports_feature(AdbdAuthFeature feature);
 
-}
+#endif  //!__ANDROID__ || __ANDROID_API__ >= 30
+__END_DECLS
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index d01233c..5857ecb 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -1,13 +1,16 @@
 LIBADBD_AUTH {
   global:
-    adbd_auth_new; # apex
-    adbd_auth_delete; # apex
-    adbd_auth_run; # apex
-    adbd_auth_get_public_keys; #apex
-    adbd_auth_notify_auth; # apex
-    adbd_auth_notify_disconnect; # apex
-    adbd_auth_prompt_user; # apex
-    adbd_auth_supports_feature; # apex
+    adbd_auth_new; # apex introduced=30
+    adbd_auth_delete; # apex introduced=30
+    adbd_auth_run; # apex introduced=30
+    adbd_auth_get_public_keys; #apex introduced=30
+    adbd_auth_notify_auth; # apex introduced=30
+    adbd_auth_notify_disconnect; # apex introduced=30
+    adbd_auth_prompt_user; # apex introduced=30
+    adbd_auth_tls_device_connected; # apex introduced=30
+    adbd_auth_tls_device_disconnected; # apex introduced=30
+    adbd_auth_get_max_version; # apex introduced=30
+    adbd_auth_supports_feature; # apex introduced=30
   local:
     *;
 };
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index f064bd7..71d8130 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -64,8 +64,7 @@
 
 bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name,
                                             bool allowIsolated, int dumpFlags) {
-    auto manager = interface_cast<AidlServiceManager>(
-                    ProcessState::self()->getContextObject(nullptr));
+    auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
 
     bool reRegister = mRegisteredServices.count(name) > 0;
     std::string regStr = (reRegister) ? "Re-registering" : "Registering";
@@ -114,9 +113,7 @@
 void ClientCounterCallback::tryShutdown() {
     ALOGI("Trying to shut down the service. No clients in use for any service in process.");
 
-    // This makes the same assumption as IServiceManager.cpp. Could dedupe if used in more places.
-    auto manager = interface_cast<AidlServiceManager>(
-            ProcessState::self()->getContextObject(nullptr));
+    auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
 
     auto unRegisterIt = mRegisteredServices.begin();
     for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 9f8d752..beab270 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -560,6 +560,13 @@
 bool Parcel::enforceInterface(const String16& interface,
                               IPCThreadState* threadState) const
 {
+    return enforceInterface(interface.string(), interface.size(), threadState);
+}
+
+bool Parcel::enforceInterface(const char16_t* interface,
+                              size_t len,
+                              IPCThreadState* threadState) const
+{
     // StrictModePolicy.
     int32_t strictPolicy = readInt32();
     if (threadState == nullptr) {
@@ -586,12 +593,15 @@
         return false;
     }
     // Interface descriptor.
-    const String16 str(readString16());
-    if (str == interface) {
+    size_t parcel_interface_len;
+    const char16_t* parcel_interface = readString16Inplace(&parcel_interface_len);
+    if (len == parcel_interface_len &&
+            (!len || !memcmp(parcel_interface, interface, len * sizeof (char16_t)))) {
         return true;
     } else {
         ALOGW("**** enforceInterface() expected '%s' but read '%s'",
-                String8(interface).string(), String8(str).string());
+              String8(interface, len).string(),
+              String8(parcel_interface, parcel_interface_len).string());
         return false;
     }
 }
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index d4bb85b..4b1a758 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -96,6 +96,9 @@
     // passed in.
     bool                enforceInterface(const String16& interface,
                                          IPCThreadState* threadState = nullptr) const;
+    bool                enforceInterface(const char16_t* interface,
+                                         size_t len,
+                                         IPCThreadState* threadState = nullptr) const;
     bool                checkInterface(IBinder*) const;
 
     void                freeData();
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 2a73dc0..c243767 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -17,7 +17,9 @@
 #define LOG_TAG "Input"
 //#define LOG_NDEBUG 0
 
+#include <cutils/compiler.h>
 #include <limits.h>
+#include <string.h>
 
 #include <input/Input.h>
 #include <input/InputDevice.h>
@@ -25,6 +27,7 @@
 
 #ifdef __ANDROID__
 #include <binder/Parcel.h>
+#include <sys/random.h>
 #endif
 
 namespace android {
@@ -40,6 +43,32 @@
     }
 }
 
+// --- IdGenerator ---
+IdGenerator::IdGenerator(Source source) : mSource(source) {}
+
+int32_t IdGenerator::nextId() const {
+    constexpr uint32_t SEQUENCE_NUMBER_MASK = ~SOURCE_MASK;
+    int32_t id = 0;
+
+// Avoid building against syscall getrandom(2) on host, which will fail build on Mac. Host doesn't
+// use sequence number so just always return mSource.
+#ifdef __ANDROID__
+    constexpr size_t BUF_LEN = sizeof(id);
+    size_t totalBytes = 0;
+    while (totalBytes < BUF_LEN) {
+        ssize_t bytes = TEMP_FAILURE_RETRY(getrandom(&id, BUF_LEN, GRND_NONBLOCK));
+        if (CC_UNLIKELY(bytes < 0)) {
+            ALOGW("Failed to fill in random number for sequence number: %s.", strerror(errno));
+            id = 0;
+            break;
+        }
+        totalBytes += bytes;
+    }
+#endif // __ANDROID__
+
+    return (id & SEQUENCE_NUMBER_MASK) | static_cast<int32_t>(mSource);
+}
+
 // --- InputEvent ---
 
 const char* inputEventTypeToString(int32_t type) {
@@ -81,8 +110,9 @@
             event.getButtonState()};
 }
 
-void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
+void InputEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                             std::array<uint8_t, 32> hmac) {
+    mId = id;
     mDeviceId = deviceId;
     mSource = source;
     mDisplayId = displayId;
@@ -90,12 +120,18 @@
 }
 
 void InputEvent::initialize(const InputEvent& from) {
+    mId = from.mId;
     mDeviceId = from.mDeviceId;
     mSource = from.mSource;
     mDisplayId = from.mDisplayId;
     mHmac = from.mHmac;
 }
 
+int32_t InputEvent::nextId() {
+    static IdGenerator idGen(IdGenerator::Source::OTHER);
+    return idGen.nextId();
+}
+
 // --- KeyEvent ---
 
 const char* KeyEvent::getLabel(int32_t keyCode) {
@@ -106,11 +142,11 @@
     return getKeyCodeByLabel(label);
 }
 
-void KeyEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
+void KeyEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                           std::array<uint8_t, 32> hmac, int32_t action, int32_t flags,
                           int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
                           nsecs_t downTime, nsecs_t eventTime) {
-    InputEvent::initialize(deviceId, source, displayId, hmac);
+    InputEvent::initialize(id, deviceId, source, displayId, hmac);
     mAction = action;
     mFlags = flags;
     mKeyCode = keyCode;
@@ -269,7 +305,7 @@
 
 // --- MotionEvent ---
 
-void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
+void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                              std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
                              int32_t flags, int32_t edgeFlags, int32_t metaState,
                              int32_t buttonState, MotionClassification classification, float xScale,
@@ -278,7 +314,7 @@
                              nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
                              const PointerProperties* pointerProperties,
                              const PointerCoords* pointerCoords) {
-    InputEvent::initialize(deviceId, source, displayId, hmac);
+    InputEvent::initialize(id, deviceId, source, displayId, hmac);
     mAction = action;
     mActionButton = actionButton;
     mFlags = flags;
@@ -303,7 +339,8 @@
 }
 
 void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
-    InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId, other->mHmac);
+    InputEvent::initialize(other->mId, other->mDeviceId, other->mSource, other->mDisplayId,
+                           other->mHmac);
     mAction = other->mAction;
     mActionButton = other->mActionButton;
     mFlags = other->mFlags;
@@ -511,6 +548,7 @@
         return BAD_VALUE;
     }
 
+    mId = parcel->readInt32();
     mDeviceId = parcel->readInt32();
     mSource = parcel->readUint32();
     mDisplayId = parcel->readInt32();
@@ -572,6 +610,7 @@
     parcel->writeInt32(pointerCount);
     parcel->writeInt32(sampleCount);
 
+    parcel->writeInt32(mId);
     parcel->writeInt32(mDeviceId);
     parcel->writeUint32(mSource);
     parcel->writeInt32(mDisplayId);
@@ -641,8 +680,8 @@
 
 // --- FocusEvent ---
 
-void FocusEvent::initialize(bool hasFocus, bool inTouchMode) {
-    InputEvent::initialize(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
+void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) {
+    InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
                            ADISPLAY_ID_NONE, INVALID_HMAC);
     mHasFocus = hasFocus;
     mInTouchMode = inTouchMode;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index d25a5cc..7335b30 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -139,6 +139,8 @@
         case InputMessage::Type::KEY: {
             // uint32_t seq
             msg->body.key.seq = body.key.seq;
+            // int32_t eventId
+            msg->body.key.eventId = body.key.eventId;
             // nsecs_t eventTime
             msg->body.key.eventTime = body.key.eventTime;
             // int32_t deviceId
@@ -168,6 +170,8 @@
         case InputMessage::Type::MOTION: {
             // uint32_t seq
             msg->body.motion.seq = body.motion.seq;
+            // int32_t eventId
+            msg->body.motion.eventId = body.motion.eventId;
             // nsecs_t eventTime
             msg->body.motion.eventTime = body.motion.eventTime;
             // int32_t deviceId
@@ -234,6 +238,7 @@
         }
         case InputMessage::Type::FOCUS: {
             msg->body.focus.seq = body.focus.seq;
+            msg->body.focus.eventId = body.focus.eventId;
             msg->body.focus.hasFocus = body.focus.hasFocus;
             msg->body.focus.inTouchMode = body.focus.inTouchMode;
             break;
@@ -432,11 +437,12 @@
 InputPublisher::~InputPublisher() {
 }
 
-status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t source,
-                                         int32_t displayId, std::array<uint8_t, 32> hmac,
-                                         int32_t action, int32_t flags, int32_t keyCode,
-                                         int32_t scanCode, int32_t metaState, int32_t repeatCount,
-                                         nsecs_t downTime, nsecs_t eventTime) {
+status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId,
+                                         int32_t source, int32_t displayId,
+                                         std::array<uint8_t, 32> hmac, int32_t action,
+                                         int32_t flags, int32_t keyCode, int32_t scanCode,
+                                         int32_t metaState, int32_t repeatCount, nsecs_t downTime,
+                                         nsecs_t eventTime) {
     if (ATRACE_ENABLED()) {
         std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
                 mChannel->getName().c_str(), keyCode);
@@ -458,6 +464,7 @@
     InputMessage msg;
     msg.header.type = InputMessage::Type::KEY;
     msg.body.key.seq = seq;
+    msg.body.key.eventId = eventId;
     msg.body.key.deviceId = deviceId;
     msg.body.key.source = source;
     msg.body.key.displayId = displayId;
@@ -474,7 +481,7 @@
 }
 
 status_t InputPublisher::publishMotionEvent(
-        uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId,
+        uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
         std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
         int32_t edgeFlags, int32_t metaState, int32_t buttonState,
         MotionClassification classification, float xScale, float yScale, float xOffset,
@@ -515,6 +522,7 @@
     InputMessage msg;
     msg.header.type = InputMessage::Type::MOTION;
     msg.body.motion.seq = seq;
+    msg.body.motion.eventId = eventId;
     msg.body.motion.deviceId = deviceId;
     msg.body.motion.source = source;
     msg.body.motion.displayId = displayId;
@@ -545,7 +553,8 @@
     return mChannel->sendMessage(&msg);
 }
 
-status_t InputPublisher::publishFocusEvent(uint32_t seq, bool hasFocus, bool inTouchMode) {
+status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus,
+                                           bool inTouchMode) {
     if (ATRACE_ENABLED()) {
         std::string message =
                 StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s, inTouchMode=%s)",
@@ -557,6 +566,7 @@
     InputMessage msg;
     msg.header.type = InputMessage::Type::FOCUS;
     msg.body.focus.seq = seq;
+    msg.body.focus.eventId = eventId;
     msg.body.focus.hasFocus = hasFocus ? 1 : 0;
     msg.body.focus.inTouchMode = inTouchMode ? 1 : 0;
     return mChannel->sendMessage(&msg);
@@ -1142,14 +1152,16 @@
 }
 
 void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
-    event->initialize(msg->body.key.deviceId, msg->body.key.source, msg->body.key.displayId,
-                      msg->body.key.hmac, msg->body.key.action, msg->body.key.flags,
-                      msg->body.key.keyCode, msg->body.key.scanCode, msg->body.key.metaState,
-                      msg->body.key.repeatCount, msg->body.key.downTime, msg->body.key.eventTime);
+    event->initialize(msg->body.key.eventId, msg->body.key.deviceId, msg->body.key.source,
+                      msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action,
+                      msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode,
+                      msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime,
+                      msg->body.key.eventTime);
 }
 
 void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) {
-    event->initialize(msg->body.focus.hasFocus == 1, msg->body.focus.inTouchMode == 1);
+    event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus == 1,
+                      msg->body.focus.inTouchMode == 1);
 }
 
 void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
@@ -1161,7 +1173,7 @@
         pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
     }
 
-    event->initialize(msg->body.motion.deviceId, msg->body.motion.source,
+    event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                       msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                       msg->body.motion.actionButton, msg->body.motion.flags,
                       msg->body.motion.edgeFlags, msg->body.motion.metaState,
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 6f9b162..cb68165 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -487,9 +487,9 @@
         int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
     outEvents.push();
     KeyEvent& event = outEvents.editTop();
-    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
-                     down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState,
-                     0, time, time);
+    event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+                     INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode,
+                     0, metaState, 0, time, time);
 }
 
 void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index fb21d5e..3b57146 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -2,6 +2,7 @@
 cc_test {
     name: "libinput_tests",
     srcs: [
+        "IdGenerator_test.cpp",
         "InputChannel_test.cpp",
         "InputDevice_test.cpp",
         "InputEvent_test.cpp",
diff --git a/libs/input/tests/IdGenerator_test.cpp b/libs/input/tests/IdGenerator_test.cpp
new file mode 100644
index 0000000..f7fc3c0
--- /dev/null
+++ b/libs/input/tests/IdGenerator_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <input/Input.h>
+#include <ios>
+#include <memory>
+#include <unordered_set>
+
+namespace android::test {
+
+class IdGeneratorTest : public testing::TestWithParam<IdGenerator::Source> {
+protected:
+    void SetUp() override { mGenerator.reset(new IdGenerator(GetParam())); }
+
+    std::unique_ptr<IdGenerator> mGenerator;
+};
+
+TEST_P(IdGeneratorTest, GenerateRandomNumber) {
+    for (int i = 0; i < 500; ++i) {
+        mGenerator->nextId();
+    }
+}
+
+TEST_P(IdGeneratorTest, GenerateRandomNumberWithProperFlag) {
+    for (int i = 0; i < 500; ++i) {
+        int32_t id = mGenerator->nextId();
+        IdGenerator::Source source = IdGenerator::getSource(id);
+        EXPECT_EQ(source, GetParam())
+                << std::hex << "Generator generated a value with wrong source. Value: 0x" << id
+                << " Source: 0x" << static_cast<int32_t>(source);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(SourceInstantiation, IdGeneratorTest,
+                         testing::Values(IdGenerator::Source::INPUT_READER,
+                                         IdGenerator::Source::INPUT_DISPATCHER,
+                                         IdGenerator::Source::OTHER));
+} // namespace android::test
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index d0f7618..553dc4c 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -182,10 +182,12 @@
     // Initialize and get properties.
     constexpr nsecs_t ARBITRARY_DOWN_TIME = 1;
     constexpr nsecs_t ARBITRARY_EVENT_TIME = 2;
-    event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, HMAC, AKEY_EVENT_ACTION_DOWN,
+    const int32_t id = InputEvent::nextId();
+    event.initialize(id, 2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, HMAC, AKEY_EVENT_ACTION_DOWN,
                      AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121, AMETA_ALT_ON, 1,
                      ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
 
+    ASSERT_EQ(id, event.getId());
     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
     ASSERT_EQ(2, event.getDeviceId());
     ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
@@ -222,12 +224,16 @@
     static constexpr float X_OFFSET = 1;
     static constexpr float Y_OFFSET = 1.1;
 
+    int32_t mId;
+
     void initializeEventWithHistory(MotionEvent* event);
     void assertEqualsEventWithHistory(const MotionEvent* event);
 };
 
 
 void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
+    mId = InputEvent::nextId();
+
     PointerProperties pointerProperties[2];
     pointerProperties[0].clear();
     pointerProperties[0].id = 1;
@@ -257,10 +263,10 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
-    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC, AMOTION_EVENT_ACTION_MOVE, 0,
-                      AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP,
-                      AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE,
-                      X_SCALE, Y_SCALE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+    event->initialize(mId, 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC,
+                      AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
+                      AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
+                      MotionClassification::NONE, X_SCALE, Y_SCALE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
                       AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                       ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties,
                       pointerCoords);
@@ -308,6 +314,7 @@
 
 void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
     // Check properties.
+    ASSERT_EQ(mId, event->getId());
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
     ASSERT_EQ(2, event->getDeviceId());
     ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
@@ -577,8 +584,8 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, INVALID_HMAC,
-                     AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
+    event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID,
+                     INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0 /*xOffset*/,
                      0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
@@ -642,10 +649,10 @@
     }
 
     for (MotionClassification classification : classifications) {
-        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC,
-                         AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
-                         0, classification, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, 0,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION,
+        event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN,
+                         DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+                         AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification, 1 /*xScale*/,
+                         1 /*yScale*/, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                          AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/,
                          pointerCount, pointerProperties, pointerCoords);
         ASSERT_EQ(classification, event.getClassification());
@@ -663,10 +670,10 @@
         pointerCoords[i].clear();
     }
 
-    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC,
-                     AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
-                     MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, 0,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/,
+    event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
+                     INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
+                     AMETA_NONE, 0, MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0,
+                     0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/,
                      0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     event.offsetLocation(20, 60);
     ASSERT_EQ(280, event.getRawXCursorPosition());
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 885196f..8e2eec8 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -73,6 +73,7 @@
     status_t status;
 
     constexpr uint32_t seq = 15;
+    int32_t eventId = InputEvent::nextId();
     constexpr int32_t deviceId = 1;
     constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD;
     constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
@@ -88,8 +89,8 @@
     constexpr nsecs_t downTime = 3;
     constexpr nsecs_t eventTime = 4;
 
-    status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, hmac, action, flags,
-                                         keyCode, scanCode, metaState, repeatCount, downTime,
+    status = mPublisher->publishKeyEvent(seq, eventId, deviceId, source, displayId, hmac, action,
+                                         flags, keyCode, scanCode, metaState, repeatCount, downTime,
                                          eventTime);
     ASSERT_EQ(OK, status)
             << "publisher publishKeyEvent should return OK";
@@ -107,6 +108,7 @@
 
     KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
     EXPECT_EQ(seq, consumeSeq);
+    EXPECT_EQ(eventId, keyEvent->getId());
     EXPECT_EQ(deviceId, keyEvent->getDeviceId());
     EXPECT_EQ(source, keyEvent->getSource());
     EXPECT_EQ(displayId, keyEvent->getDisplayId());
@@ -139,6 +141,7 @@
     status_t status;
 
     constexpr uint32_t seq = 15;
+    int32_t eventId = InputEvent::nextId();
     constexpr int32_t deviceId = 1;
     constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
     constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
@@ -182,7 +185,7 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
     }
 
-    status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, hmac, action,
+    status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
                                             actionButton, flags, edgeFlags, metaState, buttonState,
                                             classification, xScale, yScale, xOffset, yOffset,
                                             xPrecision, yPrecision, xCursorPosition,
@@ -204,6 +207,7 @@
 
     MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
     EXPECT_EQ(seq, consumeSeq);
+    EXPECT_EQ(eventId, motionEvent->getId());
     EXPECT_EQ(deviceId, motionEvent->getDeviceId());
     EXPECT_EQ(source, motionEvent->getSource());
     EXPECT_EQ(displayId, motionEvent->getDisplayId());
@@ -277,10 +281,11 @@
     status_t status;
 
     constexpr uint32_t seq = 15;
+    int32_t eventId = InputEvent::nextId();
     constexpr bool hasFocus = true;
     constexpr bool inTouchMode = true;
 
-    status = mPublisher->publishFocusEvent(seq, hasFocus, inTouchMode);
+    status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode);
     ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
 
     uint32_t consumeSeq;
@@ -294,6 +299,7 @@
 
     FocusEvent* focusEvent = static_cast<FocusEvent*>(event);
     EXPECT_EQ(seq, consumeSeq);
+    EXPECT_EQ(eventId, focusEvent->getId());
     EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
     EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode());
 
@@ -332,8 +338,8 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0,
-                                            MotionClassification::NONE, 1 /* xScale */,
+    status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
+                                            0, 0, 0, MotionClassification::NONE, 1 /* xScale */,
                                             1 /* yScale */, 0, 0, 0, 0,
                                             AMOTION_EVENT_INVALID_CURSOR_POSITION,
                                             AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
@@ -348,8 +354,8 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(1, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0,
-                                            MotionClassification::NONE, 1 /* xScale */,
+    status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
+                                            0, 0, 0, MotionClassification::NONE, 1 /* xScale */,
                                             1 /* yScale */, 0, 0, 0, 0,
                                             AMOTION_EVENT_INVALID_CURSOR_POSITION,
                                             AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
@@ -369,8 +375,8 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(1, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0,
-                                            MotionClassification::NONE, 1 /* xScale */,
+    status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
+                                            0, 0, 0, MotionClassification::NONE, 1 /* xScale */,
                                             1 /* yScale */, 0, 0, 0, 0,
                                             AMOTION_EVENT_INVALID_CURSOR_POSITION,
                                             AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index dd127fc..1fe7bb9 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -35,6 +35,7 @@
   CHECK_OFFSET(InputMessage, body, 8);
 
   CHECK_OFFSET(InputMessage::Body::Key, seq, 0);
+  CHECK_OFFSET(InputMessage::Body::Key, eventId, 4);
   CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Key, source, 20);
@@ -49,6 +50,7 @@
   CHECK_OFFSET(InputMessage::Body::Key, downTime, 88);
 
   CHECK_OFFSET(InputMessage::Body::Motion, seq, 0);
+  CHECK_OFFSET(InputMessage::Body::Motion, eventId, 4);
   CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
@@ -74,8 +76,9 @@
   CHECK_OFFSET(InputMessage::Body::Motion, pointers, 136);
 
   CHECK_OFFSET(InputMessage::Body::Focus, seq, 0);
-  CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
-  CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 6);
+  CHECK_OFFSET(InputMessage::Body::Focus, eventId, 4);
+  CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 12);
+  CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 14);
 
   CHECK_OFFSET(InputMessage::Body::Finished, seq, 0);
   CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
@@ -95,7 +98,7 @@
                   offsetof(InputMessage::Body::Motion, pointers) +
                           sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
     static_assert(sizeof(InputMessage::Body::Finished) == 8);
-    static_assert(sizeof(InputMessage::Body::Focus) == 8);
+    static_assert(sizeof(InputMessage::Body::Focus) == 16);
 }
 
 // --- VerifiedInputEvent ---
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 731eb6a..bf452c0 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -176,11 +176,12 @@
         EXPECT_EQ(pointerIndex, pointerCount);
 
         MotionEvent event;
-        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC,
-                         action, 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
-                         AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, 1 /*xScale*/,
-                         1 /*yScale*/, 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/,
-                         0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+        event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN,
+                         DISPLAY_ID, INVALID_HMAC, action, 0 /*actionButton*/, 0 /*flags*/,
+                         AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
+                         MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0 /*xOffset*/,
+                         0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION,
                          AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/,
                          entry.eventTime.count(), pointerCount, properties, coords);
 
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index a59dbe5..4e8e840 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -21,9 +21,10 @@
 
 static KeyEvent getKeyEventWithFlags(int32_t flags) {
     KeyEvent event;
-    event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
-                     AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/,
-                     AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/);
+    event.initialize(InputEvent::nextId(), 2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD,
+                     ADISPLAY_ID_DEFAULT, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, flags,
+                     AKEYCODE_BUTTON_X, 121 /*scanCode*/, AMETA_ALT_ON, 1 /*repeatCount*/,
+                     1000 /*downTime*/, 2000 /*eventTime*/);
     return event;
 }
 
@@ -38,8 +39,8 @@
         pointerCoords[i].clear();
     }
 
-    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
-                     AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
+    event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT,
+                     INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/,
                      5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/,
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 439d9bf..4ec4e25 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -108,6 +108,7 @@
     srcs: [":libinputflinger_base_sources"],
     shared_libs: [
         "libbase",
+        "libcutils",
         "libinput",
         "liblog",
         "libutils",
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index de63977..84838ec 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -16,29 +16,32 @@
 
 #define LOG_TAG "InputListener"
 
+#define ATRACE_TAG ATRACE_TAG_INPUT
+
 //#define LOG_NDEBUG 0
 
 #include "InputListener.h"
 
+#include <android-base/stringprintf.h>
 #include <android/log.h>
 #include <math.h>
+#include <utils/Trace.h>
+
+using android::base::StringPrintf;
 
 namespace android {
 
 // --- NotifyConfigurationChangedArgs ---
 
-NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
-        uint32_t sequenceNum, nsecs_t eventTime) :
-        NotifyArgs(sequenceNum, eventTime) {
-}
+NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime)
+      : NotifyArgs(id, eventTime) {}
 
 NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
-        const NotifyConfigurationChangedArgs& other) :
-        NotifyArgs(other.sequenceNum, other.eventTime) {
-}
+        const NotifyConfigurationChangedArgs& other)
+      : NotifyArgs(other.id, other.eventTime) {}
 
 bool NotifyConfigurationChangedArgs::operator==(const NotifyConfigurationChangedArgs& rhs) const {
-    return sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime;
+    return id == rhs.id && eventTime == rhs.eventTime;
 }
 
 void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
@@ -48,37 +51,39 @@
 
 // --- NotifyKeyArgs ---
 
-NotifyKeyArgs::NotifyKeyArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
-        uint32_t source, int32_t displayId, uint32_t policyFlags,
-        int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
-        int32_t metaState, nsecs_t downTime) :
-        NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source),
-        displayId(displayId), policyFlags(policyFlags),
-        action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
-        metaState(metaState), downTime(downTime) {
-}
+NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                             int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
+                             int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime)
+      : NotifyArgs(id, eventTime),
+        deviceId(deviceId),
+        source(source),
+        displayId(displayId),
+        policyFlags(policyFlags),
+        action(action),
+        flags(flags),
+        keyCode(keyCode),
+        scanCode(scanCode),
+        metaState(metaState),
+        downTime(downTime) {}
 
-NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
-        NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId),
-        source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
-        action(other.action), flags(other.flags),
-        keyCode(other.keyCode), scanCode(other.scanCode),
-        metaState(other.metaState), downTime(other.downTime) {
-}
+NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other)
+      : NotifyArgs(other.id, other.eventTime),
+        deviceId(other.deviceId),
+        source(other.source),
+        displayId(other.displayId),
+        policyFlags(other.policyFlags),
+        action(other.action),
+        flags(other.flags),
+        keyCode(other.keyCode),
+        scanCode(other.scanCode),
+        metaState(other.metaState),
+        downTime(other.downTime) {}
 
 bool NotifyKeyArgs::operator==(const NotifyKeyArgs& rhs) const {
-    return sequenceNum == rhs.sequenceNum
-            && eventTime == rhs.eventTime
-            && deviceId == rhs.deviceId
-            && source == rhs.source
-            && displayId == rhs.displayId
-            && policyFlags == rhs.policyFlags
-            && action == rhs.action
-            && flags == rhs.flags
-            && keyCode == rhs.keyCode
-            && scanCode == rhs.scanCode
-            && metaState == rhs.metaState
-            && downTime == rhs.downTime;
+    return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId &&
+            source == rhs.source && displayId == rhs.displayId && policyFlags == rhs.policyFlags &&
+            action == rhs.action && flags == rhs.flags && keyCode == rhs.keyCode &&
+            scanCode == rhs.scanCode && metaState == rhs.metaState && downTime == rhs.downTime;
 }
 
 void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
@@ -88,15 +93,17 @@
 
 // --- NotifyMotionArgs ---
 
-NotifyMotionArgs::NotifyMotionArgs(
-        uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
-        int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
-        int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
-        int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
-        const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
-        float xCursorPosition, float yCursorPosition, nsecs_t downTime,
-        const std::vector<TouchVideoFrame>& videoFrames)
-      : NotifyArgs(sequenceNum, eventTime),
+NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                                   int32_t displayId, uint32_t policyFlags, int32_t action,
+                                   int32_t actionButton, int32_t flags, int32_t metaState,
+                                   int32_t buttonState, MotionClassification classification,
+                                   int32_t edgeFlags, uint32_t pointerCount,
+                                   const PointerProperties* pointerProperties,
+                                   const PointerCoords* pointerCoords, float xPrecision,
+                                   float yPrecision, float xCursorPosition, float yCursorPosition,
+                                   nsecs_t downTime,
+                                   const std::vector<TouchVideoFrame>& videoFrames)
+      : NotifyArgs(id, eventTime),
         deviceId(deviceId),
         source(source),
         displayId(displayId),
@@ -122,7 +129,7 @@
 }
 
 NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other)
-      : NotifyArgs(other.sequenceNum, other.eventTime),
+      : NotifyArgs(other.id, other.eventTime),
         deviceId(other.deviceId),
         source(other.source),
         displayId(other.displayId),
@@ -152,12 +159,11 @@
 }
 
 bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const {
-    bool equal = sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime &&
-            deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId &&
-            policyFlags == rhs.policyFlags && action == rhs.action &&
-            actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState &&
-            buttonState == rhs.buttonState && classification == rhs.classification &&
-            edgeFlags == rhs.edgeFlags &&
+    bool equal = id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId &&
+            source == rhs.source && displayId == rhs.displayId && policyFlags == rhs.policyFlags &&
+            action == rhs.action && actionButton == rhs.actionButton && flags == rhs.flags &&
+            metaState == rhs.metaState && buttonState == rhs.buttonState &&
+            classification == rhs.classification && edgeFlags == rhs.edgeFlags &&
             pointerCount == rhs.pointerCount
             // PointerProperties and PointerCoords are compared separately below
             && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision &&
@@ -186,23 +192,22 @@
 
 // --- NotifySwitchArgs ---
 
-NotifySwitchArgs::NotifySwitchArgs(uint32_t sequenceNum, nsecs_t eventTime, uint32_t policyFlags,
-        uint32_t switchValues, uint32_t switchMask) :
-        NotifyArgs(sequenceNum, eventTime), policyFlags(policyFlags),
-        switchValues(switchValues), switchMask(switchMask) {
-}
+NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags,
+                                   uint32_t switchValues, uint32_t switchMask)
+      : NotifyArgs(id, eventTime),
+        policyFlags(policyFlags),
+        switchValues(switchValues),
+        switchMask(switchMask) {}
 
-NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) :
-        NotifyArgs(other.sequenceNum, other.eventTime), policyFlags(other.policyFlags),
-        switchValues(other.switchValues), switchMask(other.switchMask) {
-}
+NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other)
+      : NotifyArgs(other.id, other.eventTime),
+        policyFlags(other.policyFlags),
+        switchValues(other.switchValues),
+        switchMask(other.switchMask) {}
 
 bool NotifySwitchArgs::operator==(const NotifySwitchArgs rhs) const {
-    return sequenceNum == rhs.sequenceNum
-            && eventTime == rhs.eventTime
-            && policyFlags == rhs.policyFlags
-            && switchValues == rhs.switchValues
-            && switchMask == rhs.switchMask;
+    return id == rhs.id && eventTime == rhs.eventTime && policyFlags == rhs.policyFlags &&
+            switchValues == rhs.switchValues && switchMask == rhs.switchMask;
 }
 
 void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const {
@@ -212,19 +217,14 @@
 
 // --- NotifyDeviceResetArgs ---
 
-NotifyDeviceResetArgs::NotifyDeviceResetArgs(
-        uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) :
-        NotifyArgs(sequenceNum, eventTime), deviceId(deviceId) {
-}
+NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
+      : NotifyArgs(id, eventTime), deviceId(deviceId) {}
 
-NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) :
-        NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId) {
-}
+NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other)
+      : NotifyArgs(other.id, other.eventTime), deviceId(other.deviceId) {}
 
 bool NotifyDeviceResetArgs::operator==(const NotifyDeviceResetArgs& rhs) const {
-    return sequenceNum == rhs.sequenceNum
-            && eventTime == rhs.eventTime
-            && deviceId == rhs.deviceId;
+    return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId;
 }
 
 void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const {
@@ -234,6 +234,13 @@
 
 // --- QueuedInputListener ---
 
+static inline void traceEvent(const char* functionName, int32_t id) {
+    if (ATRACE_ENABLED()) {
+        std::string message = StringPrintf("%s(id=0x%" PRIx32 ")", functionName, id);
+        ATRACE_NAME(message.c_str());
+    }
+}
+
 QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
         mInnerListener(innerListener) {
 }
@@ -247,22 +254,27 @@
 
 void QueuedInputListener::notifyConfigurationChanged(
         const NotifyConfigurationChangedArgs* args) {
+    traceEvent(__func__, args->id);
     mArgsQueue.push_back(new NotifyConfigurationChangedArgs(*args));
 }
 
 void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
+    traceEvent(__func__, args->id);
     mArgsQueue.push_back(new NotifyKeyArgs(*args));
 }
 
 void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
+    traceEvent(__func__, args->id);
     mArgsQueue.push_back(new NotifyMotionArgs(*args));
 }
 
 void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
+    traceEvent(__func__, args->id);
     mArgsQueue.push_back(new NotifySwitchArgs(*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 9a6ef21..3b18813 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -203,8 +203,9 @@
     const nsecs_t currentTime = now();
 
     MotionEvent event;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
-                     AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+                     ADISPLAY_ID_DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN,
+                     /* actionButton */ 0, /* flags */ 0,
                      /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                      1 /* xScale */, 1 /* yScale */,
                      /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
@@ -228,7 +229,7 @@
 
     const nsecs_t currentTime = now();
     // Define a valid motion event.
-    NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    NotifyMotionArgs args(/* id */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
                           ADISPLAY_ID_DEFAULT, POLICY_FLAG_PASS_TO_USER, AMOTION_EVENT_ACTION_DOWN,
                           /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0,
                           MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
@@ -258,14 +259,14 @@
     for (auto _ : state) {
         // Send ACTION_DOWN
         motionArgs.action = AMOTION_EVENT_ACTION_DOWN;
-        motionArgs.sequenceNum = 0;
+        motionArgs.id = 0;
         motionArgs.downTime = now();
         motionArgs.eventTime = motionArgs.downTime;
         dispatcher->notifyMotion(&motionArgs);
 
         // Send ACTION_UP
         motionArgs.action = AMOTION_EVENT_ACTION_UP;
-        motionArgs.sequenceNum = 1;
+        motionArgs.id = 1;
         motionArgs.eventTime = now();
         dispatcher->notifyMotion(&motionArgs);
 
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
index 6f82f4f..188212b 100644
--- a/services/inputflinger/dispatcher/Connection.cpp
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -20,11 +20,13 @@
 
 namespace android::inputdispatcher {
 
-Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor)
+Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor,
+                       const IdGenerator& idGenerator)
       : status(STATUS_NORMAL),
         inputChannel(inputChannel),
         monitor(monitor),
         inputPublisher(inputChannel),
+        inputState(idGenerator),
         inputPublisherBlocked(false) {}
 
 Connection::~Connection() {}
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index 8423010..bb3f2fe 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -58,7 +58,7 @@
     // yet received a "finished" response from the application.
     std::deque<DispatchEntry*> waitQueue;
 
-    explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
+    Connection(const sp<InputChannel>& inputChannel, bool monitor, const IdGenerator& idGenerator);
 
     inline const std::string getInputChannelName() const { return inputChannel->getName(); }
 
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index c4b3789..49630ad 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -86,8 +86,8 @@
 
 // --- EventEntry ---
 
-EventEntry::EventEntry(uint32_t sequenceNum, Type type, nsecs_t eventTime, uint32_t policyFlags)
-      : sequenceNum(sequenceNum),
+EventEntry::EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags)
+      : id(id),
         refCount(1),
         type(type),
         eventTime(eventTime),
@@ -117,8 +117,8 @@
 
 // --- ConfigurationChangedEntry ---
 
-ConfigurationChangedEntry::ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime)
-      : EventEntry(sequenceNum, Type::CONFIGURATION_CHANGED, eventTime, 0) {}
+ConfigurationChangedEntry::ConfigurationChangedEntry(int32_t id, nsecs_t eventTime)
+      : EventEntry(id, Type::CONFIGURATION_CHANGED, eventTime, 0) {}
 
 ConfigurationChangedEntry::~ConfigurationChangedEntry() {}
 
@@ -128,8 +128,8 @@
 
 // --- DeviceResetEntry ---
 
-DeviceResetEntry::DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId)
-      : EventEntry(sequenceNum, Type::DEVICE_RESET, eventTime, 0), deviceId(deviceId) {}
+DeviceResetEntry::DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId)
+      : EventEntry(id, Type::DEVICE_RESET, eventTime, 0), deviceId(deviceId) {}
 
 DeviceResetEntry::~DeviceResetEntry() {}
 
@@ -140,9 +140,8 @@
 // --- FocusEntry ---
 
 // Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries
-FocusEntry::FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp<IBinder> connectionToken,
-                       bool hasFocus)
-      : EventEntry(sequenceNum, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER),
+FocusEntry::FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus)
+      : EventEntry(id, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER),
         connectionToken(connectionToken),
         hasFocus(hasFocus) {}
 
@@ -154,11 +153,11 @@
 
 // --- KeyEntry ---
 
-KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+KeyEntry::KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
                    int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
                    int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
                    nsecs_t downTime)
-      : EventEntry(sequenceNum, Type::KEY, eventTime, policyFlags),
+      : EventEntry(id, Type::KEY, eventTime, policyFlags),
         deviceId(deviceId),
         source(source),
         displayId(displayId),
@@ -198,7 +197,7 @@
 
 // --- MotionEntry ---
 
-MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
                          int32_t displayId, uint32_t policyFlags, int32_t action,
                          int32_t actionButton, int32_t flags, int32_t metaState,
                          int32_t buttonState, MotionClassification classification,
@@ -206,7 +205,7 @@
                          float xCursorPosition, float yCursorPosition, nsecs_t downTime,
                          uint32_t pointerCount, const PointerProperties* pointerProperties,
                          const PointerCoords* pointerCoords, float xOffset, float yOffset)
-      : EventEntry(sequenceNum, Type::MOTION, eventTime, policyFlags),
+      : EventEntry(id, Type::MOTION, eventTime, policyFlags),
         eventTime(eventTime),
         deviceId(deviceId),
         source(source),
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index b5b61cc..ab481bd 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -29,9 +29,6 @@
 
 namespace android::inputdispatcher {
 
-// Sequence number for synthesized or injected events.
-constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
-
 struct EventEntry {
     enum class Type {
         CONFIGURATION_CHANGED,
@@ -56,7 +53,7 @@
         }
     }
 
-    uint32_t sequenceNum;
+    int32_t id;
     mutable int32_t refCount;
     Type type;
     nsecs_t eventTime;
@@ -79,7 +76,7 @@
      * (a key is currently pressed), but the repeat itself is generated by the framework.
      */
     inline bool isSynthesized() const {
-        return isInjected() || sequenceNum == SYNTHESIZED_EVENT_SEQUENCE_NUM;
+        return isInjected() || IdGenerator::getSource(id) != IdGenerator::Source::INPUT_READER;
     }
 
     void release();
@@ -87,13 +84,13 @@
     virtual void appendDescription(std::string& msg) const = 0;
 
 protected:
-    EventEntry(uint32_t sequenceNum, Type type, nsecs_t eventTime, uint32_t policyFlags);
+    EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags);
     virtual ~EventEntry();
     void releaseInjectionState();
 };
 
 struct ConfigurationChangedEntry : EventEntry {
-    explicit ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime);
+    explicit ConfigurationChangedEntry(int32_t id, nsecs_t eventTime);
     virtual void appendDescription(std::string& msg) const;
 
 protected:
@@ -103,7 +100,7 @@
 struct DeviceResetEntry : EventEntry {
     int32_t deviceId;
 
-    DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId);
+    DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId);
     virtual void appendDescription(std::string& msg) const;
 
 protected:
@@ -114,7 +111,7 @@
     sp<IBinder> connectionToken;
     bool hasFocus;
 
-    FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus);
+    FocusEntry(int32_t id, nsecs_t eventTime, sp<IBinder> connectionToken, bool hasFocus);
     virtual void appendDescription(std::string& msg) const;
 
 protected:
@@ -144,10 +141,9 @@
     InterceptKeyResult interceptKeyResult; // set based on the interception result
     nsecs_t interceptKeyWakeupTime;        // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER
 
-    KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
-             int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
-             int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
-             nsecs_t downTime);
+    KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+             uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
+             int32_t metaState, int32_t repeatCount, nsecs_t downTime);
     virtual void appendDescription(std::string& msg) const;
     void recycle();
 
@@ -176,13 +172,13 @@
     PointerProperties pointerProperties[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
 
-    MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
-                int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
-                int32_t flags, int32_t metaState, int32_t buttonState,
-                MotionClassification classification, int32_t edgeFlags, float xPrecision,
-                float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime,
-                uint32_t pointerCount, const PointerProperties* pointerProperties,
-                const PointerCoords* pointerCoords, float xOffset, float yOffset);
+    MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+                uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
+                int32_t metaState, int32_t buttonState, MotionClassification classification,
+                int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition,
+                float yCursorPosition, nsecs_t downTime, uint32_t pointerCount,
+                const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+                float xOffset, float yOffset);
     virtual void appendDescription(std::string& msg) const;
 
 protected:
@@ -202,7 +198,8 @@
     float windowYScale = 1.0f;
     nsecs_t deliveryTime; // time when the event was actually delivered
 
-    // Set to the resolved action and flags when the event is enqueued.
+    // Set to the resolved ID, action and flags when the event is enqueued.
+    int32_t resolvedEventId;
     int32_t resolvedAction;
     int32_t resolvedFlags;
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f9a86dd..308d19b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -302,7 +302,7 @@
     }
 
     MotionEntry* combinedMotionEntry =
-            new MotionEntry(motionEntry.sequenceNum, motionEntry.eventTime, motionEntry.deviceId,
+            new MotionEntry(motionEntry.id, motionEntry.eventTime, motionEntry.deviceId,
                             motionEntry.source, motionEntry.displayId, motionEntry.policyFlags,
                             motionEntry.action, motionEntry.actionButton, motionEntry.flags,
                             motionEntry.metaState, motionEntry.buttonState,
@@ -383,6 +383,7 @@
       : mPolicy(policy),
         mPendingEvent(nullptr),
         mLastDropReason(DropReason::NOT_DROPPED),
+        mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
         mAppSwitchSawKeyDown(false),
         mAppSwitchDueTime(LONG_LONG_MAX),
         mNextUnblockedEvent(nullptr),
@@ -925,14 +926,15 @@
             (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED);
     if (entry->refCount == 1) {
         entry->recycle();
+        entry->id = mIdGenerator.nextId();
         entry->eventTime = currentTime;
         entry->policyFlags = policyFlags;
         entry->repeatCount += 1;
     } else {
         KeyEntry* newEntry =
-                new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, entry->deviceId,
-                             entry->source, entry->displayId, policyFlags, entry->action,
-                             entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
+                new KeyEntry(mIdGenerator.nextId(), currentTime, entry->deviceId, entry->source,
+                             entry->displayId, policyFlags, entry->action, entry->flags,
+                             entry->keyCode, entry->scanCode, entry->metaState,
                              entry->repeatCount + 1, entry->downTime);
 
         mKeyRepeatState.lastKeyEntry = newEntry;
@@ -981,7 +983,7 @@
 
 void InputDispatcher::enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) {
     FocusEntry* focusEntry =
-            new FocusEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, now(), window.getToken(), hasFocus);
+            new FocusEntry(mIdGenerator.nextId(), now(), window.getToken(), hasFocus);
     enqueueInboundEventLocked(focusEntry);
 }
 
@@ -1076,7 +1078,7 @@
         setInjectionResult(entry,
                            *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
                                                              : INPUT_EVENT_INJECTION_FAILED);
-        mReporter->reportDroppedKey(entry->sequenceNum);
+        mReporter->reportDroppedKey(entry->id);
         return true;
     }
 
@@ -2188,8 +2190,8 @@
                                                  const InputTarget& inputTarget) {
     if (ATRACE_ENABLED()) {
         std::string message =
-                StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",
-                             connection->getInputChannelName().c_str(), eventEntry->sequenceNum);
+                StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
+                             connection->getInputChannelName().c_str(), eventEntry->id);
         ATRACE_NAME(message.c_str());
     }
 #if DEBUG_DISPATCH_CYCLE
@@ -2244,9 +2246,8 @@
                                                    const InputTarget& inputTarget) {
     if (ATRACE_ENABLED()) {
         std::string message =
-                StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32
-                             ")",
-                             connection->getInputChannelName().c_str(), eventEntry->sequenceNum);
+                StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
+                             connection->getInputChannelName().c_str(), eventEntry->id);
         ATRACE_NAME(message.c_str());
     }
 
@@ -2300,6 +2301,7 @@
     switch (newEntry->type) {
         case EventEntry::Type::KEY: {
             const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*newEntry);
+            dispatchEntry->resolvedEventId = keyEntry.id;
             dispatchEntry->resolvedAction = keyEntry.action;
             dispatchEntry->resolvedFlags = keyEntry.flags;
 
@@ -2316,6 +2318,11 @@
 
         case EventEntry::Type::MOTION: {
             const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*newEntry);
+            // Assign a default value to dispatchEntry that will never be generated by InputReader,
+            // and assign a InputDispatcher value if it doesn't change in the if-else chain below.
+            constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
+                    static_cast<int32_t>(IdGenerator::Source::OTHER);
+            dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
             if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
             } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
@@ -2328,6 +2335,7 @@
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
             } else {
                 dispatchEntry->resolvedAction = motionEntry.action;
+                dispatchEntry->resolvedEventId = motionEntry.id;
             }
             if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
                 !connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
@@ -2358,6 +2366,17 @@
                 return; // skip the inconsistent event
             }
 
+            dispatchEntry->resolvedEventId =
+                    dispatchEntry->resolvedEventId == DEFAULT_RESOLVED_EVENT_ID
+                    ? mIdGenerator.nextId()
+                    : motionEntry.id;
+            if (ATRACE_ENABLED() && dispatchEntry->resolvedEventId != motionEntry.id) {
+                std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
+                                                   ") to MotionEvent(id=0x%" PRIx32 ").",
+                                                   motionEntry.id, dispatchEntry->resolvedEventId);
+                ATRACE_NAME(message.c_str());
+            }
+
             dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
                                             inputTarget.inputChannel->getConnectionToken());
 
@@ -2439,14 +2458,16 @@
                 std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
 
                 // Publish the key event.
-                status = connection->inputPublisher
-                                 .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId,
-                                                  keyEntry->source, keyEntry->displayId,
-                                                  std::move(hmac), dispatchEntry->resolvedAction,
-                                                  dispatchEntry->resolvedFlags, keyEntry->keyCode,
-                                                  keyEntry->scanCode, keyEntry->metaState,
-                                                  keyEntry->repeatCount, keyEntry->downTime,
-                                                  keyEntry->eventTime);
+                status =
+                        connection->inputPublisher
+                                .publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
+                                                 keyEntry->deviceId, keyEntry->source,
+                                                 keyEntry->displayId, std::move(hmac),
+                                                 dispatchEntry->resolvedAction,
+                                                 dispatchEntry->resolvedFlags, keyEntry->keyCode,
+                                                 keyEntry->scanCode, keyEntry->metaState,
+                                                 keyEntry->repeatCount, keyEntry->downTime,
+                                                 keyEntry->eventTime);
                 break;
             }
 
@@ -2495,9 +2516,11 @@
 
                 // Publish the motion event.
                 status = connection->inputPublisher
-                                 .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId,
-                                                     motionEntry->source, motionEntry->displayId,
-                                                     std::move(hmac), dispatchEntry->resolvedAction,
+                                 .publishMotionEvent(dispatchEntry->seq,
+                                                     dispatchEntry->resolvedEventId,
+                                                     motionEntry->deviceId, motionEntry->source,
+                                                     motionEntry->displayId, std::move(hmac),
+                                                     dispatchEntry->resolvedAction,
                                                      motionEntry->actionButton,
                                                      dispatchEntry->resolvedFlags,
                                                      motionEntry->edgeFlags, motionEntry->metaState,
@@ -2516,6 +2539,7 @@
             case EventEntry::Type::FOCUS: {
                 FocusEntry* focusEntry = static_cast<FocusEntry*>(eventEntry);
                 status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
+                                                                      focusEntry->id,
                                                                       focusEntry->hasFocus,
                                                                       mInTouchMode);
                 break;
@@ -2921,10 +2945,17 @@
         }
     }
 
+    int32_t newId = mIdGenerator.nextId();
+    if (ATRACE_ENABLED()) {
+        std::string message = StringPrintf("Split MotionEvent(id=0x%" PRIx32
+                                           ") to MotionEvent(id=0x%" PRIx32 ").",
+                                           originalMotionEntry.id, newId);
+        ATRACE_NAME(message.c_str());
+    }
     MotionEntry* splitMotionEntry =
-            new MotionEntry(originalMotionEntry.sequenceNum, originalMotionEntry.eventTime,
-                            originalMotionEntry.deviceId, originalMotionEntry.source,
-                            originalMotionEntry.displayId, originalMotionEntry.policyFlags, action,
+            new MotionEntry(newId, originalMotionEntry.eventTime, originalMotionEntry.deviceId,
+                            originalMotionEntry.source, originalMotionEntry.displayId,
+                            originalMotionEntry.policyFlags, action,
                             originalMotionEntry.actionButton, originalMotionEntry.flags,
                             originalMotionEntry.metaState, originalMotionEntry.buttonState,
                             originalMotionEntry.classification, originalMotionEntry.edgeFlags,
@@ -2951,7 +2982,7 @@
         std::scoped_lock _l(mLock);
 
         ConfigurationChangedEntry* newEntry =
-                new ConfigurationChangedEntry(args->sequenceNum, args->eventTime);
+                new ConfigurationChangedEntry(args->id, args->eventTime);
         needWake = enqueueInboundEventLocked(newEntry);
     } // release lock
 
@@ -3030,9 +3061,9 @@
     accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);
 
     KeyEvent event;
-    event.initialize(args->deviceId, args->source, args->displayId, INVALID_HMAC, args->action,
-                     flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime,
-                     args->eventTime);
+    event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
+                     args->action, flags, keyCode, args->scanCode, metaState, repeatCount,
+                     args->downTime, args->eventTime);
 
     android::base::Timer t;
     mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
@@ -3057,7 +3088,7 @@
         }
 
         KeyEntry* newEntry =
-                new KeyEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source,
+                new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
                              args->displayId, policyFlags, args->action, flags, keyCode,
                              args->scanCode, metaState, repeatCount, args->downTime);
 
@@ -3076,15 +3107,15 @@
 
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
-          ", policyFlags=0x%x, "
+    ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
+          "displayId=%" PRId32 ", policyFlags=0x%x, "
           "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
           "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
           "yCursorPosition=%f, downTime=%" PRId64,
-          args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
-          args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
-          args->edgeFlags, args->xPrecision, args->yPrecision, args->xCursorPosition,
-          args->yCursorPosition, args->downTime);
+          args->id, args->eventTime, args->deviceId, args->source, args->displayId,
+          args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
+          args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
+          args->xCursorPosition, args->yCursorPosition, args->downTime);
     for (uint32_t i = 0; i < args->pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
               "x=%f, y=%f, pressure=%f, size=%f, "
@@ -3125,7 +3156,7 @@
             mLock.unlock();
 
             MotionEvent event;
-            event.initialize(args->deviceId, args->source, args->displayId, INVALID_HMAC,
+            event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
                              args->action, args->actionButton, args->flags, args->edgeFlags,
                              args->metaState, args->buttonState, args->classification, 1 /*xScale*/,
                              1 /*yScale*/, 0 /* xOffset */, 0 /* yOffset */, args->xPrecision,
@@ -3143,7 +3174,7 @@
 
         // Just enqueue a new motion event.
         MotionEntry* newEntry =
-                new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source,
+                new MotionEntry(args->id, args->eventTime, args->deviceId, args->source,
                                 args->displayId, policyFlags, args->action, args->actionButton,
                                 args->flags, args->metaState, args->buttonState,
                                 args->classification, args->edgeFlags, args->xPrecision,
@@ -3187,7 +3218,7 @@
         std::scoped_lock _l(mLock);
 
         DeviceResetEntry* newEntry =
-                new DeviceResetEntry(args->sequenceNum, args->eventTime, args->deviceId);
+                new DeviceResetEntry(args->id, args->eventTime, args->deviceId);
         needWake = enqueueInboundEventLocked(newEntry);
     } // release lock
 
@@ -3227,7 +3258,7 @@
             accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action,
                                     /*byref*/ keyCode, /*byref*/ metaState);
             KeyEvent keyEvent;
-            keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+            keyEvent.initialize(incomingKey.getId(), VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
                                 incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
                                 incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
                                 incomingKey.getDownTime(), incomingKey.getEventTime());
@@ -3247,11 +3278,12 @@
 
             mLock.lock();
             KeyEntry* injectedEntry =
-                    new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
-                                 VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(),
-                                 policyFlags, action, flags, keyEvent.getKeyCode(),
-                                 keyEvent.getScanCode(), keyEvent.getMetaState(),
-                                 keyEvent.getRepeatCount(), keyEvent.getDownTime());
+                    new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(),
+                                 VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+                                 incomingKey.getDisplayId(), policyFlags, action, flags,
+                                 incomingKey.getKeyCode(), incomingKey.getScanCode(),
+                                 incomingKey.getMetaState(), incomingKey.getRepeatCount(),
+                                 incomingKey.getDownTime());
             injectedEntries.push(injectedEntry);
             break;
         }
@@ -3281,13 +3313,12 @@
             const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
             const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
             MotionEntry* injectedEntry =
-                    new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
-                                    VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
-                                    motionEvent->getDisplayId(), policyFlags, action, actionButton,
-                                    motionEvent->getFlags(), motionEvent->getMetaState(),
-                                    motionEvent->getButtonState(), motionEvent->getClassification(),
-                                    motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
-                                    motionEvent->getYPrecision(),
+                    new MotionEntry(motionEvent->getId(), *sampleEventTimes, VIRTUAL_KEYBOARD_ID,
+                                    motionEvent->getSource(), motionEvent->getDisplayId(),
+                                    policyFlags, action, actionButton, motionEvent->getFlags(),
+                                    motionEvent->getMetaState(), motionEvent->getButtonState(),
+                                    motionEvent->getClassification(), motionEvent->getEdgeFlags(),
+                                    motionEvent->getXPrecision(), motionEvent->getYPrecision(),
                                     motionEvent->getRawXCursorPosition(),
                                     motionEvent->getRawYCursorPosition(),
                                     motionEvent->getDownTime(), uint32_t(pointerCount),
@@ -3298,7 +3329,7 @@
                 sampleEventTimes += 1;
                 samplePointerCoords += pointerCount;
                 MotionEntry* nextInjectedEntry =
-                        new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
+                        new MotionEntry(motionEvent->getId(), *sampleEventTimes,
                                         VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
                                         motionEvent->getDisplayId(), policyFlags, action,
                                         actionButton, motionEvent->getFlags(),
@@ -4226,7 +4257,7 @@
             return BAD_VALUE;
         }
 
-        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
+        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
 
         int fd = inputChannel->getFd();
         mConnectionsByFd[fd] = connection;
@@ -4255,7 +4286,7 @@
             return BAD_VALUE;
         }
 
-        sp<Connection> connection = new Connection(inputChannel, true /*monitor*/);
+        sp<Connection> connection = new Connection(inputChannel, true /*monitor*/, mIdGenerator);
 
         const int fd = inputChannel->getFd();
         mConnectionsByFd[fd] = connection;
@@ -4630,7 +4661,7 @@
     if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) {
         if (!handled) {
             // Report the key as unhandled, since the fallback was not handled.
-            mReporter->reportUnhandledKey(keyEntry->sequenceNum);
+            mReporter->reportUnhandledKey(keyEntry->id);
         }
         return false;
     }
@@ -4795,7 +4826,7 @@
 #endif
 
             // Report the key as unhandled, since there is no fallback key.
-            mReporter->reportUnhandledKey(keyEntry->sequenceNum);
+            mReporter->reportUnhandledKey(keyEntry->id);
         }
     }
     return false;
@@ -4817,9 +4848,9 @@
 
 KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) {
     KeyEvent event;
-    event.initialize(entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, entry.action,
-                     entry.flags, entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount,
-                     entry.downTime, entry.eventTime);
+    event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
+                     entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
+                     entry.repeatCount, entry.downTime, entry.eventTime);
     return event;
 }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 482133e..4aa47f8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -156,6 +156,8 @@
 
     DropReason mLastDropReason GUARDED_BY(mLock);
 
+    const IdGenerator mIdGenerator;
+
     // With each iteration, InputDispatcher nominally processes one queued event,
     // a timeout, or a response from an input consumer.
     // This method should only be called on the input dispatcher's own thread.
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 053598a..386056d 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -16,9 +16,11 @@
 
 #include "InputState.h"
 
+#include "InputDispatcher.h"
+
 namespace android::inputdispatcher {
 
-InputState::InputState() {}
+InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
 
 InputState::~InputState() {}
 
@@ -268,9 +270,9 @@
     std::vector<EventEntry*> events;
     for (KeyMemento& memento : mKeyMementos) {
         if (shouldCancelKey(memento, options)) {
-            events.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
-                                          memento.deviceId, memento.source, memento.displayId,
-                                          memento.policyFlags, AKEY_EVENT_ACTION_UP,
+            events.push_back(new KeyEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
+                                          memento.source, memento.displayId, memento.policyFlags,
+                                          AKEY_EVENT_ACTION_UP,
                                           memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode,
                                           memento.scanCode, memento.metaState, 0 /*repeatCount*/,
                                           memento.downTime));
@@ -281,11 +283,10 @@
         if (shouldCancelMotion(memento, options)) {
             const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
                                                     : AMOTION_EVENT_ACTION_CANCEL;
-            events.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
-                                             memento.deviceId, memento.source, memento.displayId,
-                                             memento.policyFlags, action, 0 /*actionButton*/,
-                                             memento.flags, AMETA_NONE, 0 /*buttonState*/,
-                                             MotionClassification::NONE,
+            events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
+                                             memento.source, memento.displayId, memento.policyFlags,
+                                             action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
+                                             0 /*buttonState*/, MotionClassification::NONE,
                                              AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
                                              memento.yPrecision, memento.xCursorPosition,
                                              memento.yCursorPosition, memento.downTime,
@@ -332,16 +333,15 @@
                     : AMOTION_EVENT_ACTION_POINTER_DOWN
                             | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 
-            events.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
-                                             memento.deviceId, memento.source, memento.displayId,
-                                             memento.policyFlags, action, 0 /*actionButton*/,
-                                             memento.flags, AMETA_NONE, 0 /*buttonState*/,
-                                             MotionClassification::NONE,
+            events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
+                                             memento.source, memento.displayId, memento.policyFlags,
+                                             action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
+                                             0 /*buttonState*/, MotionClassification::NONE,
                                              AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
                                              memento.yPrecision, memento.xCursorPosition,
                                              memento.yCursorPosition, memento.downTime,
-                                             pointerCount, pointerProperties,
-                                             pointerCoords, 0 /*xOffset*/, 0 /*yOffset*/));
+                                             pointerCount, pointerProperties, pointerCoords,
+                                             0 /*xOffset*/, 0 /*yOffset*/));
         }
 
         memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index 08266ae..d97a664 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -30,7 +30,7 @@
  * synthesized when events are dropped. */
 class InputState {
 public:
-    InputState();
+    explicit InputState(const IdGenerator& idGenerator);
     ~InputState();
 
     // Returns true if there is no state to be canceled.
@@ -111,6 +111,8 @@
         void mergePointerStateTo(MotionMemento& other) const;
     };
 
+    const IdGenerator& mIdGenerator; // InputDispatcher owns it so we won't have dangling reference.
+
     std::vector<KeyMemento> mKeyMementos;
     std::vector<MotionMemento> mMotionMementos;
     KeyedVector<int32_t, int32_t> mFallbackKeys;
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 0dcd2f9..f8d0150 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -31,13 +31,12 @@
 
 /* Superclass of all input event argument objects */
 struct NotifyArgs {
-    uint32_t sequenceNum;
+    int32_t id;
     nsecs_t eventTime;
 
-    inline NotifyArgs() : sequenceNum(0), eventTime(0) { }
+    inline NotifyArgs() : id(0), eventTime(0) {}
 
-    inline explicit NotifyArgs(uint32_t sequenceNum, nsecs_t eventTime) :
-            sequenceNum(sequenceNum), eventTime(eventTime) { }
+    inline explicit NotifyArgs(int32_t id, nsecs_t eventTime) : id(id), eventTime(eventTime) {}
 
     virtual ~NotifyArgs() { }
 
@@ -52,7 +51,7 @@
 
     bool operator==(const NotifyConfigurationChangedArgs& rhs) const;
 
-    NotifyConfigurationChangedArgs(uint32_t sequenceNum, nsecs_t eventTime);
+    NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime);
 
     NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
 
@@ -77,9 +76,9 @@
 
     inline NotifyKeyArgs() { }
 
-    NotifyKeyArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
-            int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime);
+    NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                  int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
+                  int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime);
 
     bool operator==(const NotifyKeyArgs& rhs) const;
 
@@ -125,7 +124,7 @@
 
     inline NotifyMotionArgs() { }
 
-    NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+    NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
                      int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
                      int32_t flags, int32_t metaState, int32_t buttonState,
                      MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount,
@@ -152,8 +151,8 @@
 
     inline NotifySwitchArgs() { }
 
-    NotifySwitchArgs(uint32_t sequenceNum, nsecs_t eventTime, uint32_t policyFlags,
-            uint32_t switchValues, uint32_t switchMask);
+    NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues,
+                     uint32_t switchMask);
 
     NotifySwitchArgs(const NotifySwitchArgs& other);
 
@@ -172,7 +171,7 @@
 
     inline NotifyDeviceResetArgs() { }
 
-    NotifyDeviceResetArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId);
+    NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId);
 
     NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other);
 
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index d0eee64..4b19e5e 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -449,16 +449,12 @@
     for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); });
 }
 
-void InputDevice::fadePointer() {
-    for_each_mapper([](InputMapper& mapper) { mapper.fadePointer(); });
-}
-
 void InputDevice::bumpGeneration() {
     mGeneration = mContext->bumpGeneration();
 }
 
 void InputDevice::notifyReset(nsecs_t when) {
-    NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId);
+    NotifyDeviceResetArgs args(mContext->getNextId(), when, mId);
     mContext->getListener()->notifyDeviceReset(&args);
 }
 
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index cbfa702..657a134 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -46,7 +46,6 @@
       : mContext(this),
         mEventHub(eventHub),
         mPolicy(policy),
-        mNextSequenceNum(1),
         mGlobalMetaState(0),
         mGeneration(1),
         mNextInputDeviceId(END_RESERVED_ID),
@@ -313,7 +312,7 @@
     updateGlobalMetaStateLocked();
 
     // Enqueue configuration changed.
-    NotifyConfigurationChangedArgs args(mContext.getNextSequenceNum(), when);
+    NotifyConfigurationChangedArgs args(mContext.getNextId(), when);
     mQueuedListener->notifyConfigurationChanged(&args);
 }
 
@@ -326,6 +325,10 @@
               InputReaderConfiguration::changesToString(changes).c_str());
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
+        if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
+            updatePointerDisplayLocked();
+        }
+
         if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
             mEventHub->requestReopenDevices();
         } else {
@@ -387,10 +390,43 @@
     }
 }
 
+sp<PointerControllerInterface> InputReader::getPointerControllerLocked(int32_t deviceId) {
+    sp<PointerControllerInterface> controller = mPointerController.promote();
+    if (controller == nullptr) {
+        controller = mPolicy->obtainPointerController(deviceId);
+        mPointerController = controller;
+        updatePointerDisplayLocked();
+    }
+    return controller;
+}
+
+void InputReader::updatePointerDisplayLocked() {
+    sp<PointerControllerInterface> controller = mPointerController.promote();
+    if (controller == nullptr) {
+        return;
+    }
+
+    std::optional<DisplayViewport> viewport =
+            mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
+    if (!viewport) {
+        ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input "
+              "mapper. Fall back to default display",
+              mConfig.defaultPointerDisplayId);
+        viewport = mConfig.getDisplayViewportById(ADISPLAY_ID_DEFAULT);
+    }
+    if (!viewport) {
+        ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to"
+              " PointerController.");
+        return;
+    }
+
+    controller->setDisplayViewport(*viewport);
+}
+
 void InputReader::fadePointerLocked() {
-    for (auto& devicePair : mDevices) {
-        std::shared_ptr<InputDevice>& device = devicePair.second;
-        device->fadePointer();
+    sp<PointerControllerInterface> controller = mPointerController.promote();
+    if (controller != nullptr) {
+        controller->fade(PointerControllerInterface::TRANSITION_GRADUAL);
     }
 }
 
@@ -660,7 +696,8 @@
 
 // --- InputReader::ContextImpl ---
 
-InputReader::ContextImpl::ContextImpl(InputReader* reader) : mReader(reader) {}
+InputReader::ContextImpl::ContextImpl(InputReader* reader)
+      : mReader(reader), mIdGenerator(IdGenerator::Source::INPUT_READER) {}
 
 void InputReader::ContextImpl::updateGlobalMetaState() {
     // lock is already held by the input loop
@@ -688,6 +725,11 @@
     mReader->fadePointerLocked();
 }
 
+sp<PointerControllerInterface> InputReader::ContextImpl::getPointerController(int32_t deviceId) {
+    // lock is already held by the input loop
+    return mReader->getPointerControllerLocked(deviceId);
+}
+
 void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) {
     // lock is already held by the input loop
     mReader->requestTimeoutAtTimeLocked(when);
@@ -719,8 +761,8 @@
     return mReader->mEventHub.get();
 }
 
-uint32_t InputReader::ContextImpl::getNextSequenceNum() {
-    return (mReader->mNextSequenceNum)++;
+int32_t InputReader::ContextImpl::getNextId() {
+    return mIdGenerator.nextId();
 }
 
 } // namespace android
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index aaa0d26..71313fc 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -88,8 +88,6 @@
     int32_t getMetaState();
     void updateMetaState(int32_t keyCode);
 
-    void fadePointer();
-
     void bumpGeneration();
 
     void notifyReset(nsecs_t when);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 31d82f1..693ec30 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -23,6 +23,7 @@
 #include "InputReaderContext.h"
 #include "InputThread.h"
 
+#include <PointerControllerInterface.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 
@@ -93,6 +94,7 @@
 
     class ContextImpl : public InputReaderContext {
         InputReader* mReader;
+        IdGenerator mIdGenerator;
 
     public:
         explicit ContextImpl(InputReader* reader);
@@ -102,6 +104,7 @@
         virtual void disableVirtualKeysUntil(nsecs_t time) override;
         virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override;
         virtual void fadePointer() override;
+        virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) override;
         virtual void requestTimeoutAtTime(nsecs_t when) override;
         virtual int32_t bumpGeneration() override;
         virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override;
@@ -109,7 +112,7 @@
         virtual InputReaderPolicyInterface* getPolicy() override;
         virtual InputListenerInterface* getListener() override;
         virtual EventHubInterface* getEventHub() override;
-        virtual uint32_t getNextSequenceNum() override;
+        virtual int32_t getNextId() override;
     } mContext;
 
     friend class ContextImpl;
@@ -130,9 +133,6 @@
 
     InputReaderConfiguration mConfig;
 
-    // used by InputReaderContext::getNextSequenceNum() as a counter for event sequence numbers
-    uint32_t mNextSequenceNum;
-
     // The event queue.
     static const int EVENT_BUFFER_SIZE = 256;
     RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
@@ -159,6 +159,10 @@
     void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices);
     void dispatchExternalStylusState(const StylusState& state);
 
+    // The PointerController that is shared among all the input devices that need it.
+    wp<PointerControllerInterface> mPointerController;
+    sp<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId);
+    void updatePointerDisplayLocked();
     void fadePointerLocked();
 
     int32_t mGeneration;
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index e14fbbe..85701e4 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -28,6 +28,7 @@
 class InputListenerInterface;
 class InputMapper;
 class InputReaderPolicyInterface;
+class PointerControllerInterface;
 struct StylusState;
 
 /* Internal interface used by individual input devices to access global input device state
@@ -45,6 +46,7 @@
     virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) = 0;
 
     virtual void fadePointer() = 0;
+    virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) = 0;
 
     virtual void requestTimeoutAtTime(nsecs_t when) = 0;
     virtual int32_t bumpGeneration() = 0;
@@ -56,7 +58,7 @@
     virtual InputListenerInterface* getListener() = 0;
     virtual EventHubInterface* getEventHub() = 0;
 
-    virtual uint32_t getNextSequenceNum() = 0;
+    virtual int32_t getNextId() = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 520a4a4..887ab53 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -132,7 +132,7 @@
                 mYPrecision = 1.0f;
                 mXScale = 1.0f;
                 mYScale = 1.0f;
-                mPointerController = getPolicy()->obtainPointerController(getDeviceId());
+                mPointerController = getContext()->getPointerController(getDeviceId());
                 break;
             case Parameters::MODE_NAVIGATION:
                 mSource = AINPUT_SOURCE_TRACKBALL;
@@ -168,7 +168,7 @@
         }
         bumpGeneration();
         if (changes) {
-            NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId());
+            NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
             getListener()->notifyDeviceReset(&args);
         }
     }
@@ -189,34 +189,10 @@
             }
         }
 
-        // Update the PointerController if viewports changed.
-        if (mParameters.mode == Parameters::MODE_POINTER) {
-            updatePointerControllerDisplayViewport(*config);
-        }
         bumpGeneration();
     }
 }
 
-void CursorInputMapper::updatePointerControllerDisplayViewport(
-        const InputReaderConfiguration& config) {
-    std::optional<DisplayViewport> viewport =
-            config.getDisplayViewportById(config.defaultPointerDisplayId);
-    if (!viewport) {
-        ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input "
-              "mapper. Fall back to default display",
-              config.defaultPointerDisplayId);
-        viewport = config.getDisplayViewportById(ADISPLAY_ID_DEFAULT);
-    }
-
-    if (!viewport) {
-        ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to"
-              " PointerController.");
-        return;
-    }
-
-    mPointerController->setDisplayViewport(*viewport);
-}
-
 void CursorInputMapper::configureParameters() {
     mParameters.mode = Parameters::MODE_POINTER;
     String8 cursorModeString;
@@ -398,8 +374,8 @@
             while (!released.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                 buttonState &= ~actionButton;
-                NotifyMotionArgs releaseArgs(getContext()->getNextSequenceNum(), when,
-                                             getDeviceId(), mSource, displayId, policyFlags,
+                NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(),
+                                             mSource, displayId, policyFlags,
                                              AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
                                              metaState, buttonState, MotionClassification::NONE,
                                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -410,11 +386,11 @@
             }
         }
 
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, motionEventAction, 0, 0, metaState,
-                              currentButtonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
-                              mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
+                              MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                              &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
+                              xCursorPosition, yCursorPosition, downTime,
                               /* videoFrames */ {});
         getListener()->notifyMotion(&args);
 
@@ -423,8 +399,8 @@
             while (!pressed.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                 buttonState |= actionButton;
-                NotifyMotionArgs pressArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
-                                           mSource, displayId, policyFlags,
+                NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                           displayId, policyFlags,
                                            AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                                            metaState, buttonState, MotionClassification::NONE,
                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -439,10 +415,9 @@
 
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
-            NotifyMotionArgs hoverArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
-                                       mSource, displayId, policyFlags,
-                                       AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                                       currentButtonState, MotionClassification::NONE,
+            NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                       displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+                                       0, metaState, currentButtonState, MotionClassification::NONE,
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
                                        yCursorPosition, downTime, /* videoFrames */ {});
@@ -454,10 +429,9 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-            NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
-                                        mSource, displayId, policyFlags,
-                                        AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
-                                        currentButtonState, MotionClassification::NONE,
+            NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                        displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+                                        metaState, currentButtonState, MotionClassification::NONE,
                                         AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                         &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
                                         yCursorPosition, downTime, /* videoFrames */ {});
@@ -481,12 +455,6 @@
     }
 }
 
-void CursorInputMapper::fadePointer() {
-    if (mPointerController != nullptr) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-    }
-}
-
 std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
     if (mParameters.hasAssociatedDisplay) {
         if (mParameters.mode == Parameters::MODE_POINTER) {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 94ab306..f65ac39 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -66,8 +66,6 @@
 
     virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
 
-    virtual void fadePointer() override;
-
     virtual std::optional<int32_t> getAssociatedDisplayId() override;
 
 private:
@@ -117,7 +115,6 @@
     void dumpParameters(std::string& dump);
 
     void sync(nsecs_t when);
-    void updatePointerControllerDisplayViewport(const InputReaderConfiguration& config);
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index c5f99c9..a8fe39a 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -71,8 +71,6 @@
 
 void InputMapper::updateExternalStylusState(const StylusState& state) {}
 
-void InputMapper::fadePointer() {}
-
 status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) {
     return getDeviceContext().getAbsoluteAxisInfo(axis, axisInfo);
 }
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 09888bf..949c7ea 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -71,7 +71,6 @@
 
     virtual void updateExternalStylusState(const StylusState& state);
 
-    virtual void fadePointer();
     virtual std::optional<int32_t> getAssociatedDisplayId() { return std::nullopt; }
 
 protected:
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 7c3b1d9..030a846 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -333,10 +333,9 @@
     // TODO: Use the input device configuration to control this behavior more finely.
     uint32_t policyFlags = 0;
 
-    NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(),
-                          AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-                          AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
-                          MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+    NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK,
+                          ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+                          buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
                           &pointerProperties, &pointerCoords, 0, 0,
                           AMOTION_EVENT_INVALID_CURSOR_POSITION,
                           AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index ab354a2..7be4a58 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -348,9 +348,8 @@
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
 
-    NotifyKeyArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                       getDisplayId(), policyFlags,
-                       down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
+                       policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                        AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
     getListener()->notifyKey(&args);
 }
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index ed93f14..9885889 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -119,9 +119,9 @@
         int32_t metaState = getContext()->getGlobalMetaState();
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
 
-        NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(),
-                                    mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0,
-                                    0, metaState, /* buttonState */ 0, MotionClassification::NONE,
+        NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
+                                    displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+                                    metaState, /* buttonState */ 0, MotionClassification::NONE,
                                     AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                     &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                                     AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index e79aeb2..4f73681 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -56,7 +56,7 @@
 void SwitchInputMapper::sync(nsecs_t when) {
     if (mUpdatedSwitchMask) {
         uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
-        NotifySwitchArgs args(getContext()->getNextSequenceNum(), when, 0 /*policyFlags*/,
+        NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/,
                               updatedSwitchValues, mUpdatedSwitchMask);
         getListener()->notifySwitch(&args);
 
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index efa3d6d..2a3e263 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -65,8 +65,8 @@
          (currentButtonState & buttonState)) ||
         (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
          !(currentButtonState & buttonState))) {
-        NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId,
-                           policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when);
+        NotifyKeyArgs args(context->getNextId(), when, deviceId, source, displayId, policyFlags,
+                           action, 0, keyCode, 0, context->getGlobalMetaState(), when);
         context->getListener()->notifyKey(&args);
     }
 }
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b3a6df8..bbc8e53 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -386,7 +386,7 @@
     if (changes && resetNeeded) {
         // Send reset, unless this is the first time the device has been configured,
         // in which case the reader will call reset itself after all mappers are ready.
-        NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId());
+        NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
         getListener()->notifyDeviceReset(&args);
     }
 }
@@ -756,16 +756,11 @@
         mOrientedRanges.clear();
     }
 
-    // Create or update pointer controller if needed.
+    // Create pointer controller if needed.
     if (mDeviceMode == DEVICE_MODE_POINTER ||
         (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
-        if (mPointerController == nullptr || viewportChanged) {
-            mPointerController = getPolicy()->obtainPointerController(getDeviceId());
-            // Set the DisplayViewport for the PointerController to the default pointer display
-            // that is recommended by the configuration before using it.
-            std::optional<DisplayViewport> defaultViewport =
-                    mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
-            mPointerController->setDisplayViewport(defaultViewport.value_or(mViewport));
+        if (mPointerController == nullptr) {
+            mPointerController = getContext()->getPointerController(getDeviceId());
         }
     } else {
         mPointerController.clear();
@@ -1829,9 +1824,9 @@
     int32_t metaState = getContext()->getGlobalMetaState();
     policyFlags |= POLICY_FLAG_VIRTUAL;
 
-    NotifyKeyArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(),
-                       AINPUT_SOURCE_KEYBOARD, mViewport.displayId, policyFlags, keyEventAction,
-                       keyEventFlags, keyCode, scanCode, metaState, downTime);
+    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
+                       mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode,
+                       scanCode, metaState, downTime);
     getListener()->notifyKey(&args);
 }
 
@@ -2503,11 +2498,11 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
         const int32_t displayId = mPointerController->getDisplayId();
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                              metaState, buttonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
-                              0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                              buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+                              1, &pointerProperties, &pointerCoords, 0, 0, x, y,
+                              mPointerGesture.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -3423,8 +3418,8 @@
         mPointerSimple.down = false;
 
         // Send up.
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
                               mLastRawState.buttonState, MotionClassification::NONE,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
                               &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
@@ -3437,9 +3432,9 @@
         mPointerSimple.hovering = false;
 
         // Send hover exit.
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0,
-                              metaState, mLastRawState.buttonState, MotionClassification::NONE,
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+                              mLastRawState.buttonState, MotionClassification::NONE,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
                               &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
                               xCursorPosition, yCursorPosition, mPointerSimple.downTime,
@@ -3453,7 +3448,7 @@
             mPointerSimple.downTime = when;
 
             // Send down.
-            NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
+            NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
                                   displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
                                   metaState, mCurrentRawState.buttonState,
                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
@@ -3464,8 +3459,8 @@
         }
 
         // Send move.
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
                               mCurrentRawState.buttonState, MotionClassification::NONE,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
                               &mPointerSimple.currentCoords, mOrientedXPrecision,
@@ -3479,7 +3474,7 @@
             mPointerSimple.hovering = true;
 
             // Send hover enter.
-            NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
+            NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
                                   displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
                                   metaState, mCurrentRawState.buttonState,
                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
@@ -3490,9 +3485,9 @@
         }
 
         // Send hover move.
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                              metaState, mCurrentRawState.buttonState, MotionClassification::NONE,
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                              mCurrentRawState.buttonState, MotionClassification::NONE,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
                               &mPointerSimple.currentCoords, mOrientedXPrecision,
                               mOrientedYPrecision, xCursorPosition, yCursorPosition,
@@ -3512,8 +3507,8 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource,
-                              displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
+                              policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
                               mCurrentRawState.buttonState, MotionClassification::NONE,
                               AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
                               &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
@@ -3586,8 +3581,8 @@
     std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
     std::for_each(frames.begin(), frames.end(),
                   [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
-    NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, deviceId, source, displayId,
-                          policyFlags, action, actionButton, flags, metaState, buttonState,
+    NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
+                          action, actionButton, flags, metaState, buttonState,
                           MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
                           pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
                           downTime, std::move(frames));
@@ -3624,12 +3619,6 @@
     return changed;
 }
 
-void TouchInputMapper::fadePointer() {
-    if (mPointerController != nullptr) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-    }
-}
-
 void TouchInputMapper::cancelTouch(nsecs_t when) {
     abortPointerUsage(when, 0 /*policyFlags*/);
     abortTouches(when, 0 /* policyFlags*/);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 3a61206..e21a33a 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -148,7 +148,6 @@
     virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
                                        const int32_t* keyCodes, uint8_t* outFlags) override;
 
-    virtual void fadePointer() override;
     virtual void cancelTouch(nsecs_t when) override;
     virtual void timeoutExpired(nsecs_t when) override;
     virtual void updateExternalStylusState(const StylusState& state) override;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 2fb1b65..d30c4f1 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -16,13 +16,18 @@
 
 #include "../dispatcher/InputDispatcher.h"
 
+#include <android-base/stringprintf.h>
 #include <binder/Binder.h>
 #include <input/Input.h>
 
 #include <gtest/gtest.h>
 #include <linux/input.h>
+#include <cinttypes>
+#include <unordered_set>
 #include <vector>
 
+using android::base::StringPrintf;
+
 namespace android::inputdispatcher {
 
 // An arbitrary time value.
@@ -49,9 +54,9 @@
 static KeyEvent getTestKeyEvent() {
     KeyEvent event;
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
-                     AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
-                     ARBITRARY_TIME);
+    event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+                     INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
+                     ARBITRARY_TIME, ARBITRARY_TIME);
     return event;
 }
 
@@ -89,7 +94,7 @@
 
     void assertNotifySwitchWasCalled(const NotifySwitchArgs& args) {
         ASSERT_TRUE(mLastNotifySwitch);
-        // We do not check sequenceNum because it is not exposed to the policy
+        // We do not check id because it is not exposed to the policy
         EXPECT_EQ(args.eventTime, mLastNotifySwitch->eventTime);
         EXPECT_EQ(args.policyFlags, mLastNotifySwitch->policyFlags);
         EXPECT_EQ(args.switchValues, mLastNotifySwitch->switchValues);
@@ -107,6 +112,11 @@
                 << "Expected onPointerDownOutsideFocus to not have been called";
     }
 
+    void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) {
+        mConfig.keyRepeatTimeout = timeout;
+        mConfig.keyRepeatDelay = delay;
+    }
+
 private:
     std::unique_ptr<InputEvent> mFilteredEvent;
     std::optional<nsecs_t> mConfigurationChangedTime;
@@ -171,8 +181,7 @@
         /** We simply reconstruct NotifySwitchArgs in policy because InputDispatcher is
          * essentially a passthrough for notifySwitch.
          */
-        mLastNotifySwitch =
-                NotifySwitchArgs(1 /*sequenceNum*/, when, policyFlags, switchValues, switchMask);
+        mLastNotifySwitch = NotifySwitchArgs(1 /*id*/, when, policyFlags, switchValues, switchMask);
     }
 
     virtual void pokeUserActivity(nsecs_t, int32_t) {
@@ -300,7 +309,8 @@
     KeyEvent event;
 
     // Rejects undefined key actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+                     INVALID_HMAC,
                      /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
                      ARBITRARY_TIME);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -309,8 +319,8 @@
             << "Should reject key events with undefined action.";
 
     // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
-                     AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+                     INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
                      ARBITRARY_TIME, ARBITRARY_TIME);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
@@ -335,7 +345,7 @@
     constexpr MotionClassification classification = MotionClassification::NONE;
 
     // Rejects undefined motion actions.
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */,
                      1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
@@ -346,7 +356,7 @@
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_POINTER_DOWN |
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */,
@@ -358,7 +368,7 @@
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_POINTER_DOWN |
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */,
@@ -371,7 +381,7 @@
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_POINTER_UP |
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */,
@@ -383,7 +393,7 @@
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_POINTER_UP |
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */,
@@ -396,20 +406,22 @@
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
-                     edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0,
-                     0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+                     AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
+                     1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
-                     edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0,
-                     0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+                     AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
+                     1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
@@ -418,10 +430,11 @@
 
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
-                     edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0,
-                     0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+                     AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
+                     1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
@@ -429,10 +442,11 @@
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
-                     edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0,
-                     0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+                     AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
+                     1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
@@ -442,10 +456,11 @@
     // Rejects motion events with duplicate pointer ids.
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
-                     edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0,
-                     0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
+                     AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
+                     1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
@@ -457,7 +472,7 @@
 
 TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) {
     constexpr nsecs_t eventTime = 20;
-    NotifyConfigurationChangedArgs args(10 /*sequenceNum*/, eventTime);
+    NotifyConfigurationChangedArgs args(10 /*id*/, eventTime);
     mDispatcher->notifyConfigurationChanged(&args);
     ASSERT_TRUE(mDispatcher->waitForIdle());
 
@@ -465,8 +480,8 @@
 }
 
 TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) {
-    NotifySwitchArgs args(10 /*sequenceNum*/, 20 /*eventTime*/, 0 /*policyFlags*/,
-                          1 /*switchValues*/, 2 /*switchMask*/);
+    NotifySwitchArgs args(10 /*id*/, 20 /*eventTime*/, 0 /*policyFlags*/, 1 /*switchValues*/,
+                          2 /*switchMask*/);
     mDispatcher->notifySwitch(&args);
 
     // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener
@@ -748,8 +763,9 @@
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // Define a valid key down event.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, INVALID_HMAC,
-                     AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
+                     INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A,
+                     AMETA_NONE,
                      /* repeatCount */ 0, currentTime, currentTime);
 
     // Inject event until dispatch out.
@@ -777,7 +793,8 @@
 
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid motion down event.
-    event.initialize(DEVICE_ID, source, displayId, INVALID_HMAC, action, /* actionButton */ 0,
+    event.initialize(InputEvent::nextId(), DEVICE_ID, source, displayId, INVALID_HMAC, action,
+                     /* actionButton */ 0,
                      /* flags */ 0,
                      /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                      /* xScale */ 1, /* yScale */ 1, /* xOffset */ 0, /* yOffset */ 0,
@@ -805,9 +822,9 @@
 static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid key event.
-    NotifyKeyArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
-            displayId, POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0,
-            AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
+    NotifyKeyArgs args(/* id */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
+                       POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0, AKEYCODE_A, KEY_A,
+                       AMETA_NONE, currentTime);
 
     return args;
 }
@@ -834,7 +851,7 @@
 
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid motion event.
-    NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId,
+    NotifyMotionArgs args(/* id */ 0, currentTime, DEVICE_ID, source, displayId,
                           POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
                           AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                           AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties,
@@ -997,7 +1014,7 @@
 
     // When device reset happens, that key stream should be terminated with FLAG_CANCELED
     // on the app side.
-    NotifyDeviceResetArgs args(10 /*sequenceNum*/, 20 /*eventTime*/, DEVICE_ID);
+    NotifyDeviceResetArgs args(10 /*id*/, 20 /*eventTime*/, DEVICE_ID);
     mDispatcher->notifyDeviceReset(&args);
     window->consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT,
                          AKEY_EVENT_FLAG_CANCELED);
@@ -1020,7 +1037,7 @@
 
     // When device reset happens, that motion stream should be terminated with ACTION_CANCEL
     // on the app side.
-    NotifyDeviceResetArgs args(10 /*sequenceNum*/, 20 /*eventTime*/, DEVICE_ID);
+    NotifyDeviceResetArgs args(10 /*id*/, 20 /*eventTime*/, DEVICE_ID);
     mDispatcher->notifyDeviceReset(&args);
     window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT,
                          0 /*expectedFlags*/);
@@ -1345,7 +1362,7 @@
     window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
 
     motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
-    motionArgs.sequenceNum += 1;
+    motionArgs.id += 1;
     motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
     motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
                                              motionArgs.pointerCoords[0].getX() - 10);
@@ -1436,6 +1453,105 @@
     ASSERT_EQ(0, verifiedKey.repeatCount);
 }
 
+class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
+protected:
+    static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms
+    static constexpr nsecs_t KEY_REPEAT_DELAY = 40 * 1000000;   // 40 ms
+
+    sp<FakeApplicationHandle> mApp;
+    sp<FakeWindowHandle> mWindow;
+
+    virtual void SetUp() override {
+        mFakePolicy = new FakeInputDispatcherPolicy();
+        mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
+        mDispatcher = new InputDispatcher(mFakePolicy);
+        mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+        ASSERT_EQ(OK, mDispatcher->start());
+
+        setUpWindow();
+    }
+
+    void setUpWindow() {
+        mApp = new FakeApplicationHandle();
+        mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+        mWindow->setFocus(true);
+        mDispatcher->setInputWindows({mWindow}, ADISPLAY_ID_DEFAULT);
+
+        mWindow->consumeFocusEvent(true);
+    }
+
+    void sendAndConsumeKeyDown() {
+        NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+        keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
+        mDispatcher->notifyKey(&keyArgs);
+
+        // Window should receive key down event.
+        mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+    }
+
+    void expectKeyRepeatOnce(int32_t repeatCount) {
+        SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount));
+        InputEvent* repeatEvent = mWindow->consume();
+        ASSERT_NE(nullptr, repeatEvent);
+
+        uint32_t eventType = repeatEvent->getType();
+        ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, eventType);
+
+        KeyEvent* repeatKeyEvent = static_cast<KeyEvent*>(repeatEvent);
+        uint32_t eventAction = repeatKeyEvent->getAction();
+        EXPECT_EQ(AKEY_EVENT_ACTION_DOWN, eventAction);
+        EXPECT_EQ(repeatCount, repeatKeyEvent->getRepeatCount());
+    }
+
+    void sendAndConsumeKeyUp() {
+        NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+        keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
+        mDispatcher->notifyKey(&keyArgs);
+
+        // Window should receive key down event.
+        mWindow->consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT,
+                              0 /*expectedFlags*/);
+    }
+};
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
+    sendAndConsumeKeyDown();
+    for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+        expectKeyRepeatOnce(repeatCount);
+    }
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
+    sendAndConsumeKeyDown();
+    expectKeyRepeatOnce(1 /*repeatCount*/);
+    sendAndConsumeKeyUp();
+    mWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
+    sendAndConsumeKeyDown();
+    for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+        InputEvent* repeatEvent = mWindow->consume();
+        ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount;
+        EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
+                  IdGenerator::getSource(repeatEvent->getId()));
+    }
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
+    sendAndConsumeKeyDown();
+
+    std::unordered_set<int32_t> idSet;
+    for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+        InputEvent* repeatEvent = mWindow->consume();
+        ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount;
+        int32_t id = repeatEvent->getId();
+        EXPECT_EQ(idSet.end(), idSet.find(id));
+        idSet.insert(id);
+    }
+}
+
 /* Test InputDispatcher for MultiDisplay */
 class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
 public:
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index af11256..3ae8b56 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -846,7 +846,8 @@
     int32_t mGlobalMetaState;
     bool mUpdateGlobalMetaStateWasCalled;
     int32_t mGeneration;
-    uint32_t mNextSequenceNum;
+    int32_t mNextId;
+    wp<PointerControllerInterface> mPointerController;
 
 public:
     FakeInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
@@ -856,7 +857,7 @@
             mPolicy(policy),
             mListener(listener),
             mGlobalMetaState(0),
-            mNextSequenceNum(1) {}
+            mNextId(1) {}
 
     virtual ~FakeInputReaderContext() { }
 
@@ -874,6 +875,18 @@
         return mGeneration;
     }
 
+    void updatePointerDisplay() {
+        sp<PointerControllerInterface> controller = mPointerController.promote();
+        if (controller != nullptr) {
+            InputReaderConfiguration config;
+            mPolicy->getReaderConfiguration(&config);
+            auto viewport = config.getDisplayViewportById(config.defaultPointerDisplayId);
+            if (viewport) {
+                controller->setDisplayViewport(*viewport);
+            }
+        }
+    }
+
 private:
     virtual void updateGlobalMetaState() {
         mUpdateGlobalMetaStateWasCalled = true;
@@ -900,6 +913,16 @@
 
     virtual bool shouldDropVirtualKey(nsecs_t, int32_t, int32_t) { return false; }
 
+    virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) {
+        sp<PointerControllerInterface> controller = mPointerController.promote();
+        if (controller == nullptr) {
+            controller = mPolicy->obtainPointerController(deviceId);
+            mPointerController = controller;
+            updatePointerDisplay();
+        }
+        return controller;
+    }
+
     virtual void fadePointer() {
     }
 
@@ -918,9 +941,7 @@
 
     }
 
-    virtual uint32_t getNextSequenceNum() {
-        return mNextSequenceNum++;
-    }
+    virtual int32_t getNextId() { return mNextId++; }
 };
 
 
@@ -1621,7 +1642,7 @@
     ASSERT_EQ(1, event.value);
 }
 
-TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) {
+TEST_F(InputReaderTest, DeviceReset_RandomId) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
     constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
     constexpr int32_t eventHubId = 1;
@@ -1633,25 +1654,40 @@
 
     NotifyDeviceResetArgs resetArgs;
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    uint32_t prevSequenceNum = resetArgs.sequenceNum;
+    int32_t prevId = resetArgs.id;
 
     disableDevice(deviceId);
     mReader->loopOnce();
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
-    prevSequenceNum = resetArgs.sequenceNum;
+    ASSERT_NE(prevId, resetArgs.id);
+    prevId = resetArgs.id;
 
     enableDevice(deviceId);
     mReader->loopOnce();
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
-    prevSequenceNum = resetArgs.sequenceNum;
+    ASSERT_NE(prevId, resetArgs.id);
+    prevId = resetArgs.id;
 
     disableDevice(deviceId);
     mReader->loopOnce();
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
-    ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
-    prevSequenceNum = resetArgs.sequenceNum;
+    ASSERT_NE(prevId, resetArgs.id);
+    prevId = resetArgs.id;
+}
+
+TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) {
+    constexpr int32_t deviceId = 1;
+    constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+    constexpr int32_t eventHubId = 1;
+    std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
+    // Must add at least one mapper or the device will be ignored!
+    device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+    mReader->setNextDevice(device);
+    ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
+
+    NotifyDeviceResetArgs resetArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(IdGenerator::Source::INPUT_READER, IdGenerator::getSource(resetArgs.id));
 }
 
 TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
@@ -1793,21 +1829,21 @@
     NotifyConfigurationChangedArgs configChangedArgs;
     ASSERT_NO_FATAL_FAILURE(
             mTestListener->assertNotifyConfigurationChangedWasCalled(&configChangedArgs));
-    uint32_t prevSequenceNum = configChangedArgs.sequenceNum;
+    int32_t prevId = configChangedArgs.id;
     nsecs_t prevTimestamp = configChangedArgs.eventTime;
 
     NotifyKeyArgs keyArgs;
     keyboard->pressAndReleaseHomeKey();
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs));
     ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
-    ASSERT_LT(prevSequenceNum, keyArgs.sequenceNum);
-    prevSequenceNum = keyArgs.sequenceNum;
+    ASSERT_NE(prevId, keyArgs.id);
+    prevId = keyArgs.id;
     ASSERT_LE(prevTimestamp, keyArgs.eventTime);
     prevTimestamp = keyArgs.eventTime;
 
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs));
     ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
-    ASSERT_LT(prevSequenceNum, keyArgs.sequenceNum);
+    ASSERT_NE(prevId, keyArgs.id);
     ASSERT_LE(prevTimestamp, keyArgs.eventTime);
 }
 
@@ -2095,6 +2131,9 @@
     }
 
     void configureDevice(uint32_t changes) {
+        if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+            mFakeContext->updatePointerDisplay();
+        }
         mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
     }
 
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 7b3af70..3e0f136 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -1,11 +1,25 @@
 cc_library_shared {
     name: "libpowermanager",
 
-    srcs: ["IPowerManager.cpp"],
+    srcs: [
+        "IPowerManager.cpp",
+        "Temperature.cpp",
+        "CoolingDevice.cpp",
+        ":libpowermanager_aidl",
+    ],
+
+    aidl: {
+       local_include_dirs: ["."],
+       include_dirs: [
+           "frameworks/base/core/java/android/os",
+       ],
+       export_aidl_headers: true
+    },
 
     shared_libs: [
         "libutils",
         "libbinder",
+        "liblog"
     ],
 
     cflags: [
@@ -15,3 +29,22 @@
         "-Wunreachable-code",
     ],
 }
+
+cc_test {
+    name: "thermalmanager-test",
+    srcs: ["IThermalManagerTest.cpp",
+          ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libpowermanager",
+        "libbinder",
+        "libutils",
+    ],
+}
diff --git a/services/powermanager/CoolingDevice.cpp b/services/powermanager/CoolingDevice.cpp
new file mode 100644
index 0000000..ebbc1b4
--- /dev/null
+++ b/services/powermanager/CoolingDevice.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "CoolingDevice"
+
+#include <android/CoolingDevice.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace os {
+
+status_t CoolingDevice::readFromParcel(const android::Parcel *parcel) {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    parcel->readFloat(&mValue);
+    parcel->readUint32(&mType);
+    parcel->readString16(&mName);
+
+    return OK;
+}
+
+status_t CoolingDevice::writeToParcel(android::Parcel *parcel) const {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    parcel->writeFloat(mValue);
+    parcel->writeUint32(mType);
+    parcel->writeString16(mName);
+
+    return OK;
+}
+
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/services/powermanager/IThermalManagerTest.cpp b/services/powermanager/IThermalManagerTest.cpp
new file mode 100644
index 0000000..575b9ee
--- /dev/null
+++ b/services/powermanager/IThermalManagerTest.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ThermalManagerTest"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+
+#include <android/os/BnThermalStatusListener.h>
+#include <android/os/IThermalService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <condition_variable>
+#include <gtest/gtest.h>
+#include <powermanager/PowerManager.h>
+#include <utils/Log.h>
+
+using namespace android;
+using namespace android::os;
+using namespace std::chrono_literals;
+
+class IThermalServiceTest : public testing::Test,
+                            public BnThermalStatusListener{
+    public:
+        IThermalServiceTest();
+        void setThermalOverride(int level);
+        virtual binder::Status onStatusChange(int status) override;
+        int getStatusFromService();
+        void SetUp() override;
+        void TearDown() override;
+    protected:
+        sp<IThermalService> mThermalSvc;
+        std::condition_variable mCondition;
+        int mListenerStatus;
+        int mServiceStatus;
+        std::mutex mMutex;
+};
+
+IThermalServiceTest::IThermalServiceTest()
+ : mListenerStatus(0),
+   mServiceStatus(0) {
+}
+
+void IThermalServiceTest::setThermalOverride(int level) {
+    std::string cmdStr = "cmd thermalservice override-status " + std::to_string(level);
+    system(cmdStr.c_str());
+}
+
+binder::Status IThermalServiceTest::onStatusChange(int status) {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mListenerStatus = status;
+    ALOGI("IThermalServiceTest::notifyListener %d", mListenerStatus);
+    mCondition.notify_all();
+    return binder::Status::ok();
+}
+
+int IThermalServiceTest::getStatusFromService() {
+    int status;
+    binder::Status ret = mThermalSvc->getCurrentThermalStatus(&status);
+    if (ret.isOk()) {
+        return status;
+    } else {
+        return BAD_VALUE;
+    }
+}
+
+void IThermalServiceTest::SetUp() {
+    setThermalOverride(0);
+    // use checkService() to avoid blocking if thermal service is not up yet
+    sp<IBinder> binder =
+        defaultServiceManager()->checkService(String16("thermalservice"));
+    EXPECT_NE(binder, nullptr);
+    mThermalSvc = interface_cast<IThermalService>(binder);
+    EXPECT_NE(mThermalSvc, nullptr);
+    bool success = false;
+    binder::Status ret = mThermalSvc->registerThermalStatusListener(this, &success);
+    ASSERT_TRUE(success);
+    ASSERT_TRUE(ret.isOk());
+    // Wait for listener called after registration, shouldn't timeout
+    std::unique_lock<std::mutex> lock(mMutex);
+    EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+}
+
+void IThermalServiceTest::TearDown() {
+    bool success = false;
+    binder::Status ret = mThermalSvc->unregisterThermalStatusListener(this, &success);
+    ASSERT_TRUE(success);
+    ASSERT_TRUE(ret.isOk());
+}
+
+class IThermalListenerTest : public IThermalServiceTest, public testing::WithParamInterface<int32_t> {
+  public:
+    static auto PrintParam(const testing::TestParamInfo<ParamType> &info) {
+        return std::to_string(info.param);
+    }
+};
+
+TEST_P(IThermalListenerTest, TestListener) {
+    int level = GetParam();
+    std::unique_lock<std::mutex> lock(mMutex);
+    // Set the override thermal status
+    setThermalOverride(level);
+    // Wait for listener called, shouldn't timeout
+    EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+    // Check the result
+    EXPECT_EQ(level, mListenerStatus);
+    ALOGI("Thermal listener status %d, expecting %d", mListenerStatus, level);
+}
+
+INSTANTIATE_TEST_SUITE_P(TestListenerLevels, IThermalListenerTest, testing::Range(
+        static_cast<int>(ThermalStatus::THERMAL_STATUS_LIGHT),
+        static_cast<int>(ThermalStatus::THERMAL_STATUS_SHUTDOWN)),
+        IThermalListenerTest::PrintParam);
+
+class IThermalLevelTest : public IThermalServiceTest, public testing::WithParamInterface<int32_t> {
+  public:
+    static auto PrintParam(const testing::TestParamInfo<ParamType> &info) {
+        return std::to_string(info.param);
+    }
+};
+
+TEST_P(IThermalLevelTest, TestGetStatusLevel) {
+    int level = GetParam();
+    setThermalOverride(level);
+    mServiceStatus = getStatusFromService();
+    EXPECT_EQ(level, mServiceStatus);
+}
+
+INSTANTIATE_TEST_SUITE_P(TestStatusLevels, IThermalLevelTest, testing::Range(
+        static_cast<int>(ThermalStatus::THERMAL_STATUS_NONE),
+        static_cast<int>(ThermalStatus::THERMAL_STATUS_SHUTDOWN)),
+        IThermalLevelTest::PrintParam);
+
+int main(int argc, char **argv) {
+    std::unique_ptr<std::thread> binderLoop;
+    binderLoop = std::make_unique<std::thread>(
+            [&] { IPCThreadState::self()->joinThreadPool(true); });
+
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGV("Test result = %d\n", status);
+
+    return status;
+}
\ No newline at end of file
diff --git a/services/powermanager/Temperature.cpp b/services/powermanager/Temperature.cpp
new file mode 100644
index 0000000..8ec0a87
--- /dev/null
+++ b/services/powermanager/Temperature.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Temperature"
+
+#include <android/Temperature.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace os {
+
+status_t Temperature::readFromParcel(const android::Parcel *parcel) {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    parcel->readFloat(&mValue);
+    parcel->readInt32(&mType);
+    parcel->readString16(&mName);
+    parcel->readInt32(&mStatus);
+
+    return OK;
+}
+
+status_t Temperature::writeToParcel(android::Parcel *parcel) const {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    parcel->writeFloat(mValue);
+    parcel->writeInt32(mType);
+    parcel->writeString16(mName);
+    parcel->writeInt32(mStatus);
+
+    return OK;
+}
+
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5dce281..c6f1f7e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -33,6 +33,7 @@
         "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
+        "android.hardware.power-cpp",
         "libbase",
         "libbinder",
         "libbufferhubqueue",
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index c5a73f2..e740b13 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -30,6 +30,7 @@
     ~PowerAdvisor() override;
 
     MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 039db73..550ec61 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -14,14 +14,23 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+
 #undef LOG_TAG
 #define LOG_TAG "PowerAdvisor"
 
 #include <cinttypes>
 
+#include <android-base/properties.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
 
+#include <android/hardware/power/1.3/IPower.h>
+#include <android/hardware/power/IPower.h>
+#include <binder/IServiceManager.h>
+
+#include "../SurfaceFlingerProperties.h"
+
 #include "PowerAdvisor.h"
 
 namespace android {
@@ -32,11 +41,36 @@
 namespace impl {
 
 namespace V1_0 = android::hardware::power::V1_0;
+namespace V1_3 = android::hardware::power::V1_3;
 using V1_3::PowerHint;
 
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::Mode;
+using base::GetIntProperty;
+using scheduler::OneShotTimer;
+
 PowerAdvisor::~PowerAdvisor() = default;
 
-PowerAdvisor::PowerAdvisor() = default;
+namespace {
+int32_t getUpdateTimeout() {
+    // Default to a timeout of 80ms if nothing else is specified
+    static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
+    return timeout;
+}
+
+} // namespace
+
+PowerAdvisor::PowerAdvisor()
+      : mUseUpdateImminentTimer(getUpdateTimeout() > 0),
+        mUpdateImminentTimer(
+                OneShotTimer::Interval(getUpdateTimeout()),
+                /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
+                /* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) {
+    if (mUseUpdateImminentTimer) {
+        mUpdateImminentTimer.start();
+    }
+}
 
 void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
     if (expected) {
@@ -47,51 +81,170 @@
 
     const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
     if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
-        const sp<V1_3::IPower> powerHal = getPowerHal();
-        if (powerHal == nullptr) {
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper == nullptr) {
             return;
         }
-        auto ret = powerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING,
-                                                expectsExpensiveRendering);
-        // If Power HAL 1.3 was available previously but now fails,
-        // it may restart, so attempt to reconnect next time
-        if (!ret.isOk()) {
+
+        if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
+            // The HAL has become unavailable; attempt to reconnect later
             mReconnectPowerHal = true;
             return;
         }
+
         mNotifiedExpensiveRendering = expectsExpensiveRendering;
     }
 }
 
-sp<V1_3::IPower> PowerAdvisor::getPowerHal() {
-    static sp<V1_3::IPower> sPowerHal_1_3 = nullptr;
-    static bool sHasPowerHal_1_3 = true;
+void PowerAdvisor::notifyDisplayUpdateImminent() {
+    if (mSendUpdateImminent.load()) {
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper == nullptr) {
+            return;
+        }
+
+        if (!halWrapper->notifyDisplayUpdateImminent()) {
+            // The HAL has become unavailable; attempt to reconnect later
+            mReconnectPowerHal = true;
+            return;
+        }
+    }
+
+    if (mUseUpdateImminentTimer) {
+        mUpdateImminentTimer.reset();
+    }
+}
+
+class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
+public:
+    HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
+
+    ~HidlPowerHalWrapper() override = default;
+
+    static std::unique_ptr<HalWrapper> connect() {
+        // Power HAL 1.3 is not guaranteed to be available, thus we need to query
+        // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
+        // Power HAL 1.0 is always available, thus if we fail to query it, it means
+        // Power HAL is not available temporarily and we should retry later. However,
+        // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
+        // it means Power HAL 1.3 is not available at all, so we should stop trying.
+        sp<V1_3::IPower> powerHal = nullptr;
+        if (sHasPowerHal_1_3) {
+            sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
+            if (powerHal_1_0 != nullptr) {
+                // Try to cast to Power HAL 1.3
+                powerHal = V1_3::IPower::castFrom(powerHal_1_0);
+                if (powerHal == nullptr) {
+                    ALOGW("No Power HAL 1.3 service in system");
+                    sHasPowerHal_1_3 = false;
+                } else {
+                    ALOGI("Loaded Power HAL 1.3 service");
+                }
+            }
+        }
+        if (powerHal == nullptr) {
+            return nullptr;
+        }
+
+        return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
+    }
+
+    bool setExpensiveRendering(bool enabled) override {
+        ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
+        auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
+        return ret.isOk();
+    }
+
+    bool notifyDisplayUpdateImminent() override {
+        // Power HAL 1.x doesn't have a notification for this
+        ALOGV("HIDL notifyUpdateImminent received but can't send");
+        return true;
+    }
+
+private:
+    static bool sHasPowerHal_1_3;
+    const sp<V1_3::IPower> mPowerHal = nullptr;
+};
+
+bool HidlPowerHalWrapper::sHasPowerHal_1_3 = true;
+
+class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
+public:
+    AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
+        auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
+        if (!ret.isOk()) {
+            mHasExpensiveRendering = false;
+        }
+
+        ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
+                                          &mHasDisplayUpdateImminent);
+        if (!ret.isOk()) {
+            mHasDisplayUpdateImminent = false;
+        }
+    }
+
+    ~AidlPowerHalWrapper() override = default;
+
+    static std::unique_ptr<HalWrapper> connect() {
+        // This only waits if the service is actually declared
+        sp<IPower> powerHal = waitForVintfService<IPower>();
+        if (powerHal == nullptr) {
+            return nullptr;
+        }
+        ALOGI("Loaded AIDL Power HAL service");
+
+        return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+    }
+
+    bool setExpensiveRendering(bool enabled) override {
+        ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
+        if (!mHasExpensiveRendering) {
+            ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
+            return true;
+        }
+
+        auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+        return ret.isOk();
+    }
+
+    bool notifyDisplayUpdateImminent() override {
+        ALOGV("AIDL notifyDisplayUpdateImminent");
+        if (!mHasDisplayUpdateImminent) {
+            ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
+            return true;
+        }
+
+        auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
+        return ret.isOk();
+    }
+
+private:
+    const sp<IPower> mPowerHal = nullptr;
+    bool mHasExpensiveRendering = false;
+    bool mHasDisplayUpdateImminent = false;
+};
+
+PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
+    static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
 
     if (mReconnectPowerHal) {
-        sPowerHal_1_3 = nullptr;
+        sHalWrapper = nullptr;
         mReconnectPowerHal = false;
     }
 
-    // Power HAL 1.3 is not guaranteed to be available, thus we need to query
-    // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
-    // Power HAL 1.0 is always available, thus if we fail to query it, it means
-    // Power HAL is not available temporarily and we should retry later. However,
-    // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
-    // it means Power HAL 1.3 is not available at all, so we should stop trying.
-    if (sHasPowerHal_1_3 && sPowerHal_1_3 == nullptr) {
-        sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
-        if (powerHal_1_0 != nullptr) {
-            // Try to cast to Power HAL 1.3
-            sPowerHal_1_3 =  V1_3::IPower::castFrom(powerHal_1_0);
-            if (sPowerHal_1_3 == nullptr) {
-                ALOGW("No Power HAL 1.3 service in system");
-                sHasPowerHal_1_3 = false;
-            } else {
-                ALOGI("Loaded Power HAL 1.3 service");
-            }
-        }
+    if (sHalWrapper != nullptr) {
+        return sHalWrapper.get();
     }
-    return sPowerHal_1_3;
+
+    // First attempt to connect to the AIDL Power HAL
+    sHalWrapper = AidlPowerHalWrapper::connect();
+
+    // If that didn't succeed, attempt to connect to the HIDL Power HAL
+    if (sHalWrapper == nullptr) {
+        sHalWrapper = HidlPowerHalWrapper::connect();
+    }
+
+    return sHalWrapper.get();
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 5aa1f22..957d289 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,11 +22,10 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
+#include <atomic>
 #include <unordered_set>
 
-#include <android/hardware/power/1.3/IPower.h>
-#include <utils/StrongPointer.h>
-
+#include "../Scheduler/OneShotTimer.h"
 #include "DisplayIdentification.h"
 
 namespace android {
@@ -37,27 +36,40 @@
     virtual ~PowerAdvisor();
 
     virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
+    virtual void notifyDisplayUpdateImminent() = 0;
 };
 
 namespace impl {
 
-namespace V1_3 = android::hardware::power::V1_3;
-
 // PowerAdvisor is a wrapper around IPower HAL which takes into account the
 // full state of the system when sending out power hints to things like the GPU.
 class PowerAdvisor final : public Hwc2::PowerAdvisor {
 public:
+    class HalWrapper {
+    public:
+        virtual ~HalWrapper() = default;
+
+        virtual bool setExpensiveRendering(bool enabled) = 0;
+        virtual bool notifyDisplayUpdateImminent() = 0;
+    };
+
     PowerAdvisor();
     ~PowerAdvisor() override;
 
     void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
+    void notifyDisplayUpdateImminent() override;
 
 private:
-    sp<V1_3::IPower> getPowerHal();
+    HalWrapper* getPowerHal();
+
+    bool mReconnectPowerHal = false;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
-    bool mReconnectPowerHal = false;
+
+    const bool mUseUpdateImminentTimer;
+    std::atomic_bool mSendUpdateImminent = true;
+    scheduler::OneShotTimer mUpdateImminentTimer;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1da894d..ef59b55 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -368,6 +368,10 @@
     const size_t defaultListSize = MAX_LAYERS;
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+    mGraphicBufferProducerListSizeLogThreshold =
+            std::max(static_cast<int>(0.95 *
+                                      static_cast<double>(mMaxGraphicBufferProducerListSize)),
+                     1);
 
     property_get("debug.sf.luma_sampling", value, "1");
     mLumaSampling = atoi(value);
@@ -1487,11 +1491,13 @@
 
 void SurfaceFlinger::signalTransaction() {
     mScheduler->resetIdleTimer();
+    mPowerAdvisor.notifyDisplayUpdateImminent();
     mEventQueue->invalidate();
 }
 
 void SurfaceFlinger::signalLayerUpdate() {
     mScheduler->resetIdleTimer();
+    mPowerAdvisor.notifyDisplayUpdateImminent();
     mEventQueue->invalidate();
 }
 
@@ -3062,6 +3068,11 @@
                                 "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
                                 mGraphicBufferProducerList.size(),
                                 mMaxGraphicBufferProducerListSize, mNumLayers.load());
+            if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) {
+                ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+                      mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
+                      mNumLayers.load());
+            }
         }
         mLayersAdded = true;
     }
@@ -5132,6 +5143,7 @@
 
 void SurfaceFlinger::repaintEverythingForHWC() {
     mRepaintEverything = true;
+    mPowerAdvisor.notifyDisplayUpdateImminent();
     mEventQueue->invalidate();
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e4a5da1..09a3430 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -972,6 +972,10 @@
     // Can't be unordered_set because wp<> isn't hashable
     std::set<wp<IBinder>> mGraphicBufferProducerList;
     size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
+    // If there are more GraphicBufferProducers tracked by SurfaceFlinger than
+    // this threshold, then begin logging.
+    size_t mGraphicBufferProducerListSizeLogThreshold =
+            static_cast<size_t>(0.95 * static_cast<double>(MAX_LAYERS));
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved = false;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 1a611f5..f3352a5 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -305,6 +305,14 @@
     return defaultValue;
 }
 
+int32_t display_update_imminent_timeout_ms(int32_t defaultValue) {
+    auto temp = SurfaceFlingerProperties::display_update_imminent_timeout_ms();
+    if (temp.has_value()) {
+        return *temp;
+    }
+    return defaultValue;
+}
+
 #define DISPLAY_PRIMARY_SIZE 3
 
 constexpr float kSrgbRedX = 0.4123f;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 4c6e191..12c711a 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -89,6 +89,8 @@
 
 bool use_frame_rate_api(bool defaultValue);
 
+int32_t display_update_imminent_timeout_ms(int32_t defaultValue);
+
 android::ui::DisplayPrimaries getDisplayNativePrimaries();
 } // namespace sysprop
 } // namespace android
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index b19eae6..155f718 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -403,3 +403,15 @@
     access: Readonly
     prop_name: "ro.surface_flinger.use_frame_rate_api"
 }
+
+# Sets the timeout used to rate limit DISPLAY_UPDATE_IMMINENT Power HAL notifications.
+# SurfaceFlinger wakeups will trigger this boost whenever they are separated by more than this
+# duration (specified in milliseconds). A value of 0 disables the rate limit, and will result in
+# Power HAL notifications every time SF wakes up.
+prop {
+    api_name: "display_update_imminent_timeout_ms"
+    type: Integer
+    scope: Public
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index c66523a..e62c127 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -36,6 +36,11 @@
     prop_name: "ro.surface_flinger.display_primary_white"
   }
   prop {
+    api_name: "display_update_imminent_timeout_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
+  }
+  prop {
     api_name: "enable_protected_contents"
     prop_name: "ro.surface_flinger.protected_contents"
   }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 7c65f95..fe57c98 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -30,6 +30,7 @@
     ~PowerAdvisor() override;
 
     MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
 };
 
 } // namespace mock