Merge "Ensure non visible layers that have input are traversed for input" into main
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 750e170..2d64872 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -290,6 +290,17 @@
      */
     bool probablyHasInput() const;
 
+    /* Wait until there is a message in the channel.
+     *
+     * The |timeout| specifies how long to block waiting for an input event to appear. Negative
+     * values are not allowed.
+     *
+     * In some cases returning before timeout expiration can happen without a message available.
+     * This could happen after the channel was closed on the other side. Another possible reason
+     * is incorrect setup of the channel.
+     */
+    void waitForMessage(std::chrono::milliseconds timeout) const;
+
     /* Return a new object that has a duplicate of this channel's fd. */
     std::unique_ptr<InputChannel> dup() const;
 
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index ce9cd1c..7da8d51 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -31,6 +31,8 @@
 namespace android {
 namespace battery {
 
+#define REPORTED_INVALID_TIMESTAMP_DELTA_MS 60000
+
 typedef uint16_t state_t;
 
 template <class T>
@@ -171,8 +173,12 @@
         if (timestamp >= lastStateChangeTimestamp) {
             states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
         } else {
-            ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
-                  (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+            if (timestamp < lastStateChangeTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
+                ALOGE("setState is called with an earlier timestamp: %lu, "
+                      "previous timestamp: %lu\n",
+                      (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+            }
+
             // The accumulated durations have become unreliable. For example, if the timestamp
             // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
             // we would get 4000, which is greater than (last - first). This could lead to
@@ -232,8 +238,10 @@
                     }
                 }
             } else if (timestamp < lastUpdateTimestamp) {
-                ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
-                      (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+                if (timestamp < lastUpdateTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
+                    ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
+                          (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+                }
 
                 for (int i = 0; i < stateCount; i++) {
                     states[i].timeInStateSinceUpdate = 0;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index d4b8dbe..b9ab803 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -168,8 +168,8 @@
         return std::make_unique<InputSurface>(surfaceControl, width, height);
     }
 
-    InputEvent *consumeEvent(int timeoutMs = 3000) {
-        waitForEventAvailable(timeoutMs);
+    InputEvent* consumeEvent(std::chrono::milliseconds timeout = 3000ms) {
+        mClientChannel->waitForMessage(timeout);
 
         InputEvent *ev;
         uint32_t seqId;
@@ -302,15 +302,6 @@
         t.apply(true);
     }
 
-private:
-    void waitForEventAvailable(int timeoutMs) {
-        struct pollfd fd;
-
-        fd.fd = mClientChannel->getFd();
-        fd.events = POLLIN;
-        poll(&fd, 1, timeoutMs);
-    }
-
 public:
     sp<SurfaceControl> mSurfaceControl;
     std::shared_ptr<InputChannel> mClientChannel;
@@ -615,7 +606,7 @@
 
     // A tap within the surface but outside the touchable region should not be sent to the surface.
     injectTap(20, 30);
-    EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/200ms), nullptr);
 
     injectTap(31, 52);
     surface->expectTap(20, 30);
@@ -981,12 +972,12 @@
     obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222};
     obscuringSurface->showAt(100, 100);
     injectTap(101, 101);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     surface->requestFocus();
     surface->assertFocusChange(true);
     injectKey(AKEYCODE_V);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
@@ -1002,12 +993,12 @@
 
     injectTap(101, 101);
 
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     surface->requestFocus();
     surface->assertFocusChange(true);
     injectKey(AKEYCODE_V);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
@@ -1024,12 +1015,12 @@
 
     injectTap(101, 101);
 
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     surface->requestFocus();
     surface->assertFocusChange(true);
     injectKey(AKEYCODE_V);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
@@ -1046,12 +1037,12 @@
 
     injectTap(111, 111);
 
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     surface->requestFocus();
     surface->assertFocusChange(true);
     injectKey(AKEYCODE_V);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
@@ -1076,12 +1067,12 @@
 
     injectTap(101, 101);
 
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     surface->requestFocus();
     surface->assertFocusChange(true);
     injectKey(AKEYCODE_V);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) {
@@ -1116,7 +1107,7 @@
 
     // Does not receive events outside its crop
     injectTap(26, 26);
-    EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+    EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 /**
@@ -1141,7 +1132,7 @@
 
     // Does not receive events outside parent bounds
     injectTap(31, 31);
-    EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+    EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 /**
@@ -1167,7 +1158,7 @@
     // Does not receive events outside crop layer bounds
     injectTap(21, 21);
     injectTap(71, 71);
-    EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+    EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) {
@@ -1184,7 +1175,7 @@
             [&](auto &t, auto &sc) { t.reparent(sc, parent->mSurfaceControl); });
     injectTap(101, 101);
 
-    EXPECT_EQ(parent->consumeEvent(100), nullptr);
+    EXPECT_EQ(parent->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 class MultiDisplayTests : public InputSurfacesTest {
@@ -1233,7 +1224,7 @@
 
     // Touches should be dropped if the layer is on an invalid display.
     injectTapOnDisplay(101, 101, layerStack.id);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     // However, we still let the window be focused and receive keys.
     surface->requestFocus(layerStack.id);
@@ -1271,12 +1262,12 @@
 
     injectTapOnDisplay(101, 101, layerStack.id);
 
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 
     surface->requestFocus(layerStack.id);
     surface->assertFocusChange(true);
     injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
-    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+    EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
 }
 
 TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index fa094df..37de00c 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -521,11 +521,11 @@
 bool InputChannel::probablyHasInput() const {
     struct pollfd pfds = {.fd = mFd, .events = POLLIN};
     if (::poll(&pfds, /*nfds=*/1, /*timeout=*/0) <= 0) {
-        // This can be a false negative because EAGAIN and ENOMEM are not handled. The latter should
-        // be extremely rare. The EAGAIN is also unlikely because it happens only when the signal
-        // arrives while the syscall is executed, and the syscall is quick. Hitting EAGAIN too often
+        // This can be a false negative because EINTR and ENOMEM are not handled. The latter should
+        // be extremely rare. The EINTR is also unlikely because it happens only when the signal
+        // arrives while the syscall is executed, and the syscall is quick. Hitting EINTR too often
         // would be a sign of having too many signals, which is a bigger performance problem. A
-        // common tradition is to repeat the syscall on each EAGAIN, but it is not necessary here.
+        // common tradition is to repeat the syscall on each EINTR, but it is not necessary here.
         // In other words, the missing one liner is replaced by a multiline explanation.
         return false;
     }
@@ -534,6 +534,22 @@
     return (pfds.revents & POLLIN) != 0;
 }
 
+void InputChannel::waitForMessage(std::chrono::milliseconds timeout) const {
+    if (timeout < 0ms) {
+        LOG(FATAL) << "Timeout cannot be negative, received " << timeout.count();
+    }
+    struct pollfd pfds = {.fd = mFd, .events = POLLIN};
+    int ret;
+    std::chrono::time_point<std::chrono::steady_clock> stopTime =
+            std::chrono::steady_clock::now() + timeout;
+    std::chrono::milliseconds remaining = timeout;
+    do {
+        ret = ::poll(&pfds, /*nfds=*/1, /*timeout=*/remaining.count());
+        remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
+                stopTime - std::chrono::steady_clock::now());
+    } while (ret == -1 && errno == EINTR && remaining > 0ms);
+}
+
 std::unique_ptr<InputChannel> InputChannel::dup() const {
     base::unique_fd newFd(dupFd());
     return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 1baeb26..576d9d5 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -64,13 +64,6 @@
 }
 
 flag {
-  name: "remove_app_switch_drops"
-  namespace: "input"
-  description: "Remove the logic of dropping events due to pending app switch"
-  bug: "284808102"
-}
-
-flag {
   name: "disable_reject_touch_on_stylus_hover"
   namespace: "input"
   description: "Disable touch rejection when the stylus hovers the screen"
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index d4278be..8056d9a 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -29,6 +29,7 @@
 #define ANDROID_DATA_SPACE_H
 
 #include <inttypes.h>
+#include <stdint.h>
 
 #include <sys/cdefs.h>
 
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index c889b9b..fe33d94 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -98,13 +98,6 @@
 constexpr bool DEBUG_TOUCH_OCCLUSION = true;
 
 /**
- * Log debug messages about the app switch latency optimization.
- * Enable this via "adb shell setprop log.tag.InputDispatcherAppSwitch DEBUG" (requires restart)
- */
-const bool DEBUG_APP_SWITCH =
-        android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "AppSwitch");
-
-/**
  * Log debug messages about hover events.
  * Enable this via "adb shell setprop log.tag.InputDispatcherHover DEBUG" (requires restart)
  */
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index cc0d49c..2153d8a 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -164,6 +164,11 @@
                         keyCode, scanCode, metaState, repeatCount, policyFlags);
 }
 
+std::ostream& operator<<(std::ostream& out, const KeyEntry& keyEntry) {
+    out << keyEntry.getDescription();
+    return out;
+}
+
 // --- TouchModeEntry ---
 
 TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int displayId)
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index e2e13c3..a915805 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -18,6 +18,7 @@
 
 #include "InjectionState.h"
 #include "InputTarget.h"
+#include "trace/EventTrackerInterface.h"
 
 #include <gui/InputApplication.h>
 #include <input/Input.h>
@@ -125,6 +126,7 @@
     int32_t scanCode;
     int32_t metaState;
     nsecs_t downTime;
+    std::unique_ptr<trace::EventTrackerInterface> traceTracker;
 
     bool syntheticRepeat; // set to true for synthetic key repeats
 
@@ -147,6 +149,8 @@
     std::string getDescription() const override;
 };
 
+std::ostream& operator<<(std::ostream& out, const KeyEntry& motionEntry);
+
 struct MotionEntry : EventEntry {
     int32_t deviceId;
     uint32_t source;
@@ -165,6 +169,7 @@
     nsecs_t downTime;
     std::vector<PointerProperties> pointerProperties;
     std::vector<PointerCoords> pointerCoords;
+    std::unique_ptr<trace::EventTrackerInterface> traceTracker;
 
     size_t getPointerCount() const { return pointerProperties.size(); }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index e998d91..1085c94 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -72,12 +72,17 @@
 using android::os::InputEventInjectionSync;
 namespace input_flags = com::android::input::flags;
 
-// TODO(b/312714754): remove the corresponding code, as well.
-static const bool REMOVE_APP_SWITCH_DROPS = true;
-
 namespace android::inputdispatcher {
 
 namespace {
+
+template <class Entry>
+void ensureEventTraced(const Entry& entry) {
+    if (!entry.traceTracker) {
+        LOG(FATAL) << "Expected event entry to be traced, but it wasn't: " << entry;
+    }
+}
+
 // Temporarily releases a held mutex for the lifetime of the instance.
 // Named to match std::scoped_lock
 class scoped_unlock {
@@ -95,11 +100,6 @@
         android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
         HwTimeoutMultiplier());
 
-// Amount of time to allow for all pending events to be processed when an app switch
-// key is on the way.  This is used to preempt input dispatch and drop input events
-// when an application takes too long to respond and the user has pressed an app switch key.
-constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
-
 const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier();
 
 // Log a warning when an event takes longer than this to process, even if an ANR does not occur.
@@ -783,12 +783,14 @@
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy)
+      : InputDispatcher(policy, nullptr) {}
+
+InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
+                                 std::unique_ptr<trace::InputTracingBackendInterface> traceBackend)
       : mPolicy(policy),
         mPendingEvent(nullptr),
         mLastDropReason(DropReason::NOT_DROPPED),
         mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
-        mAppSwitchSawKeyDown(false),
-        mAppSwitchDueTime(LLONG_MAX),
         mNextUnblockedEvent(nullptr),
         mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),
         mDispatchEnabled(false),
@@ -807,6 +809,10 @@
     SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
 #endif
     mKeyRepeatState.lastKeyEntry = nullptr;
+
+    if (traceBackend) {
+        // TODO: Create input tracer instance.
+    }
 }
 
 InputDispatcher::~InputDispatcher() {
@@ -975,28 +981,10 @@
         return;
     }
 
-    // Optimize latency of app switches.
-    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
-    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.
-    bool isAppSwitchDue;
-    if (!REMOVE_APP_SWITCH_DROPS) {
-        isAppSwitchDue = mAppSwitchDueTime <= currentTime;
-        nextWakeupTime = std::min(nextWakeupTime, mAppSwitchDueTime);
-    }
-
     // Ready to start a new event.
     // If we don't already have a pending event, go grab one.
     if (!mPendingEvent) {
         if (mInboundQueue.empty()) {
-            if (!REMOVE_APP_SWITCH_DROPS) {
-                if (isAppSwitchDue) {
-                    // The inbound queue is empty so the app switch key we were waiting
-                    // for will never arrive.  Stop waiting for it.
-                    resetPendingAppSwitchLocked(false);
-                    isAppSwitchDue = false;
-                }
-            }
-
             // Synthesize a key repeat if appropriate.
             if (mKeyRepeatState.lastKeyEntry) {
                 if (currentTime >= mKeyRepeatState.nextRepeatTime) {
@@ -1091,16 +1079,6 @@
         case EventEntry::Type::KEY: {
             std::shared_ptr<const KeyEntry> keyEntry =
                     std::static_pointer_cast<const KeyEntry>(mPendingEvent);
-            if (!REMOVE_APP_SWITCH_DROPS) {
-                if (isAppSwitchDue) {
-                    if (isAppSwitchKeyEvent(*keyEntry)) {
-                        resetPendingAppSwitchLocked(true);
-                        isAppSwitchDue = false;
-                    } else if (dropReason == DropReason::NOT_DROPPED) {
-                        dropReason = DropReason::APP_SWITCH;
-                    }
-                }
-            }
             if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
                 dropReason = DropReason::STALE;
             }
@@ -1108,17 +1086,16 @@
                 dropReason = DropReason::BLOCKED;
             }
             done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
+            if (done && mTracer) {
+                ensureEventTraced(*keyEntry);
+                mTracer->eventProcessingComplete(*keyEntry->traceTracker);
+            }
             break;
         }
 
         case EventEntry::Type::MOTION: {
             std::shared_ptr<const MotionEntry> motionEntry =
                     std::static_pointer_cast<const MotionEntry>(mPendingEvent);
-            if (!REMOVE_APP_SWITCH_DROPS) {
-                if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
-                    dropReason = DropReason::APP_SWITCH;
-                }
-            }
             if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
                 // The event is stale. However, only drop stale events if there isn't an ongoing
                 // gesture. That would allow us to complete the processing of the current stroke.
@@ -1138,17 +1115,17 @@
                 }
             }
             done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
+            if (done && mTracer) {
+                ensureEventTraced(*motionEntry);
+                mTracer->eventProcessingComplete(*motionEntry->traceTracker);
+            }
             break;
         }
 
         case EventEntry::Type::SENSOR: {
             std::shared_ptr<const SensorEntry> sensorEntry =
                     std::static_pointer_cast<const SensorEntry>(mPendingEvent);
-            if (!REMOVE_APP_SWITCH_DROPS) {
-                if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
-                    dropReason = DropReason::APP_SWITCH;
-                }
-            }
+
             //  Sensor timestamps use SYSTEM_TIME_BOOTTIME time base, so we can't use
             // 'currentTime' here, get SYSTEM_TIME_BOOTTIME instead.
             nsecs_t bootTime = systemTime(SYSTEM_TIME_BOOTTIME);
@@ -1245,27 +1222,12 @@
         case EventEntry::Type::KEY: {
             LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
                                 "Unexpected untrusted event.");
-            // Optimize app switch latency.
-            // If the application takes too long to catch up then we drop all events preceding
-            // the app switch key.
-            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
 
-            if (!REMOVE_APP_SWITCH_DROPS) {
-                if (isAppSwitchKeyEvent(keyEntry)) {
-                    if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
-                        mAppSwitchSawKeyDown = true;
-                    } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
-                        if (mAppSwitchSawKeyDown) {
-                            if (DEBUG_APP_SWITCH) {
-                                ALOGD("App switch is pending!");
-                            }
-                            mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
-                            mAppSwitchSawKeyDown = false;
-                            needWake = true;
-                        }
-                    }
-                }
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
+            if (mTracer) {
+                ensureEventTraced(keyEntry);
             }
+
             // If a new up event comes in, and the pending event with same key code has been asked
             // to try again later because of the policy. We have to reset the intercept key wake up
             // time for it may have been handled in the policy and could be dropped.
@@ -1286,7 +1248,11 @@
         case EventEntry::Type::MOTION: {
             LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
                                 "Unexpected untrusted event.");
-            if (shouldPruneInboundQueueLocked(static_cast<const MotionEntry&>(entry))) {
+            const auto& motionEntry = static_cast<const MotionEntry&>(entry);
+            if (mTracer) {
+                ensureEventTraced(motionEntry);
+            }
+            if (shouldPruneInboundQueueLocked(motionEntry)) {
                 mNextUnblockedEvent = mInboundQueue.back();
                 needWake = true;
             }
@@ -1401,10 +1367,6 @@
             }
             reason = "inbound event was dropped because input dispatch is disabled";
             break;
-        case DropReason::APP_SWITCH:
-            ALOGI("Dropped event because of pending overdue app switch.");
-            reason = "inbound event was dropped because of pending overdue app switch";
-            break;
         case DropReason::BLOCKED:
             LOG(INFO) << "Dropping because the current application is not responding and the user "
                          "has started interacting with a different application: "
@@ -1468,33 +1430,6 @@
     }
 }
 
-static bool isAppSwitchKeyCode(int32_t keyCode) {
-    return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL ||
-            keyCode == AKEYCODE_APP_SWITCH;
-}
-
-bool InputDispatcher::isAppSwitchKeyEvent(const KeyEntry& keyEntry) {
-    return !(keyEntry.flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry.keyCode) &&
-            (keyEntry.policyFlags & POLICY_FLAG_TRUSTED) &&
-            (keyEntry.policyFlags & POLICY_FLAG_PASS_TO_USER);
-}
-
-bool InputDispatcher::isAppSwitchPendingLocked() const {
-    return mAppSwitchDueTime != LLONG_MAX;
-}
-
-void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
-    mAppSwitchDueTime = LLONG_MAX;
-
-    if (DEBUG_APP_SWITCH) {
-        if (handled) {
-            ALOGD("App switch has arrived.");
-        } else {
-            ALOGD("App switch was abandoned.");
-        }
-    }
-}
-
 bool InputDispatcher::haveCommandsLocked() const {
     return !mCommandQueue.empty();
 }
@@ -1567,6 +1502,10 @@
                                        entry->repeatCount + 1, entry->downTime);
 
     newEntry->syntheticRepeat = true;
+    if (mTracer) {
+        newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
+    }
+
     mKeyRepeatState.lastKeyEntry = newEntry;
     mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay;
     return newEntry;
@@ -1873,6 +1812,13 @@
     // Add monitor channels from event's or focused display.
     addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
 
+    if (mTracer) {
+        ensureEventTraced(*entry);
+        for (const auto& target : inputTargets) {
+            mTracer->dispatchToTargetHint(*entry->traceTracker, target);
+        }
+    }
+
     // Dispatch the key.
     dispatchEventLocked(currentTime, entry, inputTargets);
     return true;
@@ -1998,6 +1944,13 @@
     // Add monitor channels from event's or focused display.
     addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
 
+    if (mTracer) {
+        ensureEventTraced(*entry);
+        for (const auto& target : inputTargets) {
+            mTracer->dispatchToTargetHint(*entry->traceTracker, target);
+        }
+    }
+
     // Dispatch the motion.
     dispatchEventLocked(currentTime, entry, inputTargets);
     return true;
@@ -3635,6 +3588,7 @@
     PointerCoords scaledCoords[MAX_POINTERS];
     const PointerCoords* usingCoords = motionEntry.pointerCoords.data();
 
+    // TODO(b/316355518): Do not modify coords before dispatch.
     // Set the X and Y offset and X and Y scale depending on the input source.
     if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) &&
         !(dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS))) {
@@ -3710,6 +3664,9 @@
                                                   keyEntry.keyCode, keyEntry.scanCode,
                                                   keyEntry.metaState, keyEntry.repeatCount,
                                                   keyEntry.downTime, keyEntry.eventTime);
+                if (mTracer) {
+                    mTracer->traceEventDispatch(*dispatchEntry, keyEntry.traceTracker.get());
+                }
                 break;
             }
 
@@ -3718,7 +3675,11 @@
                     LOG(INFO) << "Publishing " << *dispatchEntry << " to "
                               << connection->getInputChannelName();
                 }
+                const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
                 status = publishMotionEvent(*connection, *dispatchEntry);
+                if (mTracer) {
+                    mTracer->traceEventDispatch(*dispatchEntry, motionEntry.traceTracker.get());
+                }
                 break;
             }
 
@@ -4400,6 +4361,9 @@
                                            args.deviceId, args.source, args.displayId, policyFlags,
                                            args.action, flags, keyCode, args.scanCode, metaState,
                                            repeatCount, args.downTime);
+        if (mTracer) {
+            newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
+        }
 
         needWake = enqueueInboundEventLocked(std::move(newEntry));
         mLock.unlock();
@@ -4526,6 +4490,9 @@
                                               args.yPrecision, args.xCursorPosition,
                                               args.yCursorPosition, args.downTime,
                                               args.pointerProperties, args.pointerCoords);
+        if (mTracer) {
+            newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
+        }
 
         if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
             IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
@@ -4713,6 +4680,9 @@
                                                incomingKey.getScanCode(), metaState,
                                                incomingKey.getRepeatCount(),
                                                incomingKey.getDownTime());
+            if (mTracer) {
+                injectedEntry->traceTracker = mTracer->traceInboundEvent(*injectedEntry);
+            }
             injectedEntries.push(std::move(injectedEntry));
             break;
         }
@@ -4770,6 +4740,9 @@
                                                                              samplePointerCoords +
                                                                                      pointerCount));
             transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform());
+            if (mTracer) {
+                injectedEntry->traceTracker = mTracer->traceInboundEvent(*injectedEntry);
+            }
             injectedEntries.push(std::move(injectedEntry));
             for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
                 sampleEventTimes += 1;
@@ -5843,16 +5816,6 @@
         dump += INDENT "Connections: <none>\n";
     }
 
-    dump += "input_flags::remove_app_switch_drops() = ";
-    dump += toString(REMOVE_APP_SWITCH_DROPS);
-    dump += "\n";
-    if (isAppSwitchPendingLocked()) {
-        dump += StringPrintf(INDENT "AppSwitch: pending, due in %" PRId64 "ms\n",
-                             ns2ms(mAppSwitchDueTime - now()));
-    } else {
-        dump += INDENT "AppSwitch: not pending\n";
-    }
-
     if (!mTouchModePerDisplay.empty()) {
         dump += INDENT "TouchModePerDisplay:\n";
         for (const auto& [displayId, touchMode] : mTouchModePerDisplay) {
@@ -5869,6 +5832,8 @@
                          ns2ms(mConfig.keyRepeatTimeout));
     dump += mLatencyTracker.dump(INDENT2);
     dump += mLatencyAggregator.dump(INDENT2);
+    dump += INDENT "InputTracer: ";
+    dump += mTracer == nullptr ? "Disabled" : "Enabled";
 }
 
 void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) const {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 3567288..1e11b27 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -32,6 +32,8 @@
 #include "Monitor.h"
 #include "TouchState.h"
 #include "TouchedWindow.h"
+#include "trace/InputTracerInterface.h"
+#include "trace/InputTracingBackendInterface.h"
 
 #include <attestation/HmacKeyManager.h>
 #include <gui/InputApplication.h>
@@ -82,6 +84,9 @@
     static constexpr bool kDefaultInTouchMode = true;
 
     explicit InputDispatcher(InputDispatcherPolicyInterface& policy);
+    // Constructor used for testing.
+    explicit InputDispatcher(InputDispatcherPolicyInterface&,
+                             std::unique_ptr<trace::InputTracingBackendInterface>);
     ~InputDispatcher() override;
 
     void dump(std::string& dump) const override;
@@ -155,7 +160,6 @@
     enum class DropReason {
         NOT_DROPPED,
         POLICY,
-        APP_SWITCH,
         DISABLED,
         BLOCKED,
         STALE,
@@ -172,6 +176,9 @@
     std::condition_variable mDispatcherIsAlive;
     mutable std::condition_variable mDispatcherEnteredIdle;
 
+    // Input event tracer. The tracer will only exist on builds where input tracing is allowed.
+    std::unique_ptr<trace::InputTracerInterface> mTracer GUARDED_BY(mLock);
+
     sp<Looper> mLooper;
 
     std::shared_ptr<const EventEntry> mPendingEvent GUARDED_BY(mLock);
@@ -228,14 +235,6 @@
     // Adds an event to a queue of recent events for debugging purposes.
     void addRecentEventLocked(std::shared_ptr<const EventEntry> entry) REQUIRES(mLock);
 
-    // App switch latency optimization.
-    bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
-    nsecs_t mAppSwitchDueTime GUARDED_BY(mLock);
-
-    bool isAppSwitchKeyEvent(const KeyEntry& keyEntry);
-    bool isAppSwitchPendingLocked() const REQUIRES(mLock);
-    void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
-
     // Blocked event latency optimization.  Drops old events when the user intends
     // to transfer focus to a new application.
     std::shared_ptr<const EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/trace/EventTrackerInterface.h b/services/inputflinger/dispatcher/trace/EventTrackerInterface.h
new file mode 100644
index 0000000..929820e
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/EventTrackerInterface.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::inputdispatcher::trace {
+
+/**
+ * A tracker used to track the lifecycle of a traced input event.
+ * The tracker should be stored inside the traced event. When the event goes out of scope after
+ * the dispatcher has finished processing it, the tracker will call back into the tracer to
+ * initiate cleanup.
+ */
+class EventTrackerInterface {
+public:
+    virtual ~EventTrackerInterface() = default;
+};
+
+} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/InputTracerInterface.h b/services/inputflinger/dispatcher/trace/InputTracerInterface.h
new file mode 100644
index 0000000..c6cd7de
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/InputTracerInterface.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../Entry.h"
+#include "../InputTarget.h"
+#include "EventTrackerInterface.h"
+
+namespace android::inputdispatcher::trace {
+
+/**
+ * InputTracerInterface is the tracing interface for InputDispatcher.
+ *
+ * The tracer is responsible for tracing information about input events and where they are
+ * dispatched. The trace is logged to the backend using the InputTracingBackendInterface.
+ *
+ * A normal traced event should have the following lifecycle:
+ *  - The EventTracker is obtained from traceInboundEvent(), after which point the event
+ *    should not change.
+ *  - While the event is being processed, dispatchToTargetHint() is called for each target that
+ *    the event will be eventually sent to.
+ *  - Once all targets have been determined, eventProcessingComplete() is called, at which point
+ *    the tracer will have enough information to commit the event to the trace.
+ *  - For each event that is dispatched to the client, traceEventDispatch() is called, and the
+ *    tracer will record that the event was sent to the client.
+ */
+class InputTracerInterface {
+public:
+    InputTracerInterface() = default;
+    virtual ~InputTracerInterface() = default;
+    InputTracerInterface(const InputTracerInterface&) = delete;
+    InputTracerInterface& operator=(const InputTracerInterface&) = delete;
+
+    /**
+     * Trace an input event that is being processed by InputDispatcher. The event must not be
+     * modified after it is traced to keep the traced event consistent with the event that is
+     * eventually dispatched. An EventTracker is returned for each traced event that should be used
+     * to track the event's lifecycle inside InputDispatcher.
+     */
+    virtual std::unique_ptr<EventTrackerInterface> traceInboundEvent(const EventEntry&) = 0;
+
+    /**
+     * Notify the tracer that the traced event will be sent to the given InputTarget.
+     * The tracer may change how the event is logged depending on the target. For example,
+     * events targeting certain UIDs may be logged as sensitive events.
+     * This may be called 0 or more times for each tracked event before event processing is
+     * completed.
+     */
+    virtual void dispatchToTargetHint(const EventTrackerInterface&, const InputTarget&) = 0;
+
+    /**
+     * Notify the tracer that the event processing is complete. This may be called at most once
+     * for each traced event. If a tracked event is dropped before it can be processed, it is
+     * possible that this is never called before the EventTracker is destroyed.
+     *
+     * This is used to commit the event to the trace in a timely manner, rather than always
+     * waiting for the event to go out of scope (and thus for the EventTracker to be destroyed)
+     * before committing. The point at which the event is destroyed can depend on several factors
+     * outside of our control, such as how long apps take to respond, so we don't want to depend on
+     * that.
+     */
+    virtual void eventProcessingComplete(const EventTrackerInterface&) = 0;
+
+    /**
+     * Trace an input event being successfully dispatched to a window. The dispatched event may
+     * be a previously traced inbound event, or it may be a synthesized event that has not been
+     * previously traced. For inbound events that were previously traced, the EventTracker cookie
+     * must be provided. For events that were not previously traced, the cookie must be null.
+     */
+    virtual void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface*) = 0;
+};
+
+} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
new file mode 100644
index 0000000..b430a5b
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../Entry.h"
+
+namespace android::inputdispatcher::trace {
+
+/**
+ * An interface for the tracing backend, used for setting a custom backend for testing.
+ */
+class InputTracingBackendInterface {
+public:
+    virtual ~InputTracingBackendInterface() = default;
+
+    /** Trace a KeyEvent. */
+    virtual void traceKeyEvent(const KeyEntry&) const = 0;
+
+    /** Trace a MotionEvent. */
+    virtual void traceMotionEvent(const MotionEntry&) const = 0;
+
+    /** Trace an event being sent to a window. */
+    struct WindowDispatchArgs {
+        std::variant<MotionEntry, KeyEntry> eventEntry;
+        nsecs_t deliveryTime;
+        int32_t resolvedFlags;
+        gui::Uid targetUid;
+        int64_t vsyncId;
+        int32_t windowId;
+        ui::Transform transform;
+        ui::Transform rawTransform;
+        std::array<uint8_t, 32> hmac;
+    };
+    virtual void traceWindowDispatch(const WindowDispatchArgs&) const = 0;
+};
+
+} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 48d7e55..b6ae0b3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -861,30 +861,31 @@
     explicit FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel, const std::string name)
           : mConsumer(std::move(clientChannel)), mName(name) {}
 
-    InputEvent* consume(std::chrono::milliseconds timeout, bool handled = false) {
-        InputEvent* event;
-        std::optional<uint32_t> consumeSeq = receiveEvent(timeout, &event);
+    std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = false) {
+        auto [consumeSeq, event] = receiveEvent(timeout);
         if (!consumeSeq) {
             return nullptr;
         }
         finishEvent(*consumeSeq, handled);
-        return event;
+        return std::move(event);
     }
 
     /**
      * Receive an event without acknowledging it.
      * Return the sequence number that could later be used to send finished signal.
      */
-    std::optional<uint32_t> receiveEvent(std::chrono::milliseconds timeout,
-                                         InputEvent** outEvent = nullptr) {
+    std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent(
+            std::chrono::milliseconds timeout) {
         uint32_t consumeSeq;
-        InputEvent* event;
+        std::unique_ptr<InputEvent> event;
 
         std::chrono::time_point start = std::chrono::steady_clock::now();
         status_t status = WOULD_BLOCK;
         while (status == WOULD_BLOCK) {
+            InputEvent* rawEventPtr = nullptr;
             status = mConsumer.consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq,
-                                       &event);
+                                       &rawEventPtr);
+            event = std::unique_ptr<InputEvent>(rawEventPtr);
             std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
             if (elapsed > timeout) {
                 break;
@@ -893,21 +894,17 @@
 
         if (status == WOULD_BLOCK) {
             // Just means there's no event available.
-            return std::nullopt;
+            return std::make_pair(std::nullopt, nullptr);
         }
 
         if (status != OK) {
             ADD_FAILURE() << mName.c_str() << ": consumer consume should return OK.";
-            return std::nullopt;
+            return std::make_pair(std::nullopt, nullptr);
         }
         if (event == nullptr) {
             ADD_FAILURE() << "Consumed correctly, but received NULL event from consumer";
-            return std::nullopt;
         }
-        if (outEvent != nullptr) {
-            *outEvent = event;
-        }
-        return consumeSeq;
+        return std::make_pair(consumeSeq, std::move(event));
     }
 
     /**
@@ -926,7 +923,7 @@
     void consumeEvent(InputEventType expectedEventType, int32_t expectedAction,
                       std::optional<int32_t> expectedDisplayId,
                       std::optional<int32_t> expectedFlags) {
-        InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
 
         ASSERT_NE(nullptr, event) << mName.c_str()
                                   << ": consumer should have returned non-NULL event.";
@@ -970,8 +967,8 @@
         }
     }
 
-    MotionEvent* consumeMotion() {
-        InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+    std::unique_ptr<MotionEvent> consumeMotion() {
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
 
         if (event == nullptr) {
             ADD_FAILURE() << mName << ": expected a MotionEvent, but didn't get one.";
@@ -982,17 +979,17 @@
             ADD_FAILURE() << mName << " expected a MotionEvent, got " << *event;
             return nullptr;
         }
-        return static_cast<MotionEvent*>(event);
+        return std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
     }
 
     void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
-        MotionEvent* motionEvent = consumeMotion();
+        std::unique_ptr<MotionEvent> motionEvent = consumeMotion();
         ASSERT_NE(nullptr, motionEvent) << "Did not get a motion event, but expected " << matcher;
         ASSERT_THAT(*motionEvent, matcher);
     }
 
     void consumeFocusEvent(bool hasFocus, bool inTouchMode) {
-        InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
         ASSERT_NE(nullptr, event) << mName.c_str()
                                   << ": consumer should have returned non-NULL event.";
         ASSERT_EQ(InputEventType::FOCUS, event->getType())
@@ -1001,12 +998,12 @@
         ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
                 << mName.c_str() << ": event displayId should always be NONE.";
 
-        FocusEvent* focusEvent = static_cast<FocusEvent*>(event);
-        EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
+        FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
+        EXPECT_EQ(hasFocus, focusEvent.getHasFocus());
     }
 
     void consumeCaptureEvent(bool hasCapture) {
-        const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
         ASSERT_NE(nullptr, event) << mName.c_str()
                                   << ": consumer should have returned non-NULL event.";
         ASSERT_EQ(InputEventType::CAPTURE, event->getType())
@@ -1020,7 +1017,7 @@
     }
 
     void consumeDragEvent(bool isExiting, float x, float y) {
-        const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
         ASSERT_NE(nullptr, event) << mName.c_str()
                                   << ": consumer should have returned non-NULL event.";
         ASSERT_EQ(InputEventType::DRAG, event->getType()) << "Instead of DragEvent, got " << *event;
@@ -1035,7 +1032,7 @@
     }
 
     void consumeTouchModeEvent(bool inTouchMode) {
-        const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
         ASSERT_NE(nullptr, event) << mName.c_str()
                                   << ": consumer should have returned non-NULL event.";
         ASSERT_EQ(InputEventType::TOUCH_MODE, event->getType())
@@ -1048,7 +1045,7 @@
     }
 
     void assertNoEvents() {
-        InputEvent* event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
         if (event == nullptr) {
             return;
         }
@@ -1081,7 +1078,7 @@
 
 private:
     InputConsumer mConsumer;
-    PreallocatedInputEventFactory mEventFactory;
+    DynamicInputEventFactory mEventFactory;
 
     std::string mName;
 };
@@ -1229,17 +1226,23 @@
 
     void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); }
 
-    const KeyEvent& consumeKey(bool handled = true) {
-        const InputEvent& event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
-        if (event.getType() != InputEventType::KEY) {
-            LOG(FATAL) << "Instead of key event, got " << event;
+    std::unique_ptr<KeyEvent> consumeKey(bool handled = true) {
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
+        if (event == nullptr) {
+            ADD_FAILURE() << "No event";
+            return nullptr;
         }
-        return static_cast<const KeyEvent&>(event);
+        if (event->getType() != InputEventType::KEY) {
+            ADD_FAILURE() << "Instead of key event, got " << event;
+            return nullptr;
+        }
+        return std::unique_ptr<KeyEvent>(static_cast<KeyEvent*>(event.release()));
     }
 
     void consumeKeyEvent(const ::testing::Matcher<KeyEvent>& matcher) {
-        const KeyEvent& keyEvent = consumeKey();
-        ASSERT_THAT(keyEvent, matcher);
+        std::unique_ptr<KeyEvent> keyEvent = consumeKey();
+        ASSERT_NE(nullptr, keyEvent);
+        ASSERT_THAT(*keyEvent, matcher);
     }
 
     void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
@@ -1325,14 +1328,20 @@
         mInputReceiver->consumeCaptureEvent(hasCapture);
     }
 
-    const MotionEvent& consumeMotionEvent(
+    std::unique_ptr<MotionEvent> consumeMotionEvent(
             const ::testing::Matcher<MotionEvent>& matcher = testing::_) {
-        const InputEvent& event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
-        if (event.getType() != InputEventType::MOTION) {
-            LOG(FATAL) << "Instead of motion event, got " << event;
+        std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        if (event == nullptr) {
+            ADD_FAILURE() << "No event";
+            return nullptr;
         }
-        const auto& motionEvent = static_cast<const MotionEvent&>(event);
-        EXPECT_THAT(motionEvent, matcher);
+        if (event->getType() != InputEventType::MOTION) {
+            ADD_FAILURE() << "Instead of motion event, got " << *event;
+            return nullptr;
+        }
+        std::unique_ptr<MotionEvent> motionEvent =
+                std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
+        EXPECT_THAT(*motionEvent, matcher);
         return motionEvent;
     }
 
@@ -1346,12 +1355,12 @@
         mInputReceiver->consumeTouchModeEvent(inTouchMode);
     }
 
-    std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) {
+    std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent() {
         if (mInputReceiver == nullptr) {
             ADD_FAILURE() << "Invalid receive event on window with no receiver";
-            return std::nullopt;
+            return std::make_pair(std::nullopt, nullptr);
         }
-        return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED, outEvent);
+        return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
     }
 
     void finishEvent(uint32_t sequenceNum) {
@@ -1396,15 +1405,15 @@
     static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
     friend class sp<FakeWindowHandle>;
 
-    const InputEvent& consume(std::chrono::milliseconds timeout, bool handled = true) {
+    std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) {
         if (mInputReceiver == nullptr) {
             LOG(FATAL) << "Cannot consume event from a window with no input event receiver";
         }
-        InputEvent* event = mInputReceiver->consume(timeout, handled);
+        std::unique_ptr<InputEvent> event = mInputReceiver->consume(timeout, handled);
         if (event == nullptr) {
-            LOG(FATAL) << "Consume failed: no event";
+            ADD_FAILURE() << "Consume failed: no event";
         }
-        return *event;
+        return event;
     }
 };
 
@@ -1423,7 +1432,8 @@
     }
 
     std::optional<int32_t> receiveEvent() {
-        return mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
+        return sequenceNum;
     }
 
     void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
@@ -1461,7 +1471,7 @@
         mInputReceiver.consumeMotionEvent(matcher);
     }
 
-    MotionEvent* consumeMotion() { return mInputReceiver.consumeMotion(); }
+    std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
 
     void assertNoEvents() { mInputReceiver.assertNoEvents(); }
 
@@ -3779,18 +3789,20 @@
 
     mDispatcher->waitForIdle();
 
-    const MotionEvent& motionEvent1 = window1->consumeMotionEvent();
+    std::unique_ptr<MotionEvent> motionEvent1 = window1->consumeMotionEvent();
+    ASSERT_NE(nullptr, motionEvent1);
     window2->assertNoEvents();
-    nsecs_t downTimeForWindow1 = motionEvent1.getDownTime();
-    ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime());
+    nsecs_t downTimeForWindow1 = motionEvent1->getDownTime();
+    ASSERT_EQ(motionEvent1->getDownTime(), motionEvent1->getEventTime());
 
     // Now touch down on the window with another pointer
     mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
     mDispatcher->waitForIdle();
-    const MotionEvent& motionEvent2 = window2->consumeMotionEvent();
-    nsecs_t downTimeForWindow2 = motionEvent2.getDownTime();
+    std::unique_ptr<MotionEvent> motionEvent2 = window2->consumeMotionEvent();
+    ASSERT_NE(nullptr, motionEvent2);
+    nsecs_t downTimeForWindow2 = motionEvent2->getDownTime();
     ASSERT_NE(downTimeForWindow1, downTimeForWindow2);
-    ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime());
+    ASSERT_EQ(motionEvent2->getDownTime(), motionEvent2->getEventTime());
 
     // Now move the pointer on the second window
     mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
@@ -4624,12 +4636,13 @@
                                 InputEventInjectionSync::WAIT_FOR_RESULT))
             << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
 
-    const MotionEvent& event = window->consumeMotionEvent();
-    EXPECT_EQ(POINTER_1_DOWN, event.getAction());
-    EXPECT_EQ(70, event.getX(0));  // 50 + 20
-    EXPECT_EQ(90, event.getY(0));  // 50 + 40
-    EXPECT_EQ(-10, event.getX(1)); // -30 + 20
-    EXPECT_EQ(-10, event.getY(1)); // -50 + 40
+    std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
+    ASSERT_NE(nullptr, event);
+    EXPECT_EQ(POINTER_1_DOWN, event->getAction());
+    EXPECT_EQ(70, event->getX(0));  // 50 + 20
+    EXPECT_EQ(90, event->getY(0));  // 50 + 40
+    EXPECT_EQ(-10, event->getX(1)); // -30 + 20
+    EXPECT_EQ(-10, event->getY(1)); // -50 + 40
 }
 
 /**
@@ -4895,15 +4908,16 @@
     EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
 
     // windowDefaultDisplay gets cancel
-    const MotionEvent& event = windowDefaultDisplay->consumeMotionEvent();
-    EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
+    std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
+    ASSERT_NE(nullptr, event);
+    EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
 
     // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
     // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
     // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
     // SECOND_DISPLAY_ID, the x and y coordinates are 200
-    EXPECT_EQ(100, event.getX(0));
-    EXPECT_EQ(100, event.getY(0));
+    EXPECT_EQ(100, event->getX(0));
+    EXPECT_EQ(100, event->getY(0));
 }
 
 /**
@@ -5033,18 +5047,19 @@
                                                  {PointF{150, 220}}));
 
     firstWindow->assertNoEvents();
-    const MotionEvent& event = secondWindow->consumeMotionEvent();
-    EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event.getAction());
+    std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
+    ASSERT_NE(nullptr, event);
+    EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
 
     // Ensure that the events from the "getRaw" API are in logical display coordinates.
-    EXPECT_EQ(300, event.getRawX(0));
-    EXPECT_EQ(880, event.getRawY(0));
+    EXPECT_EQ(300, event->getRawX(0));
+    EXPECT_EQ(880, event->getRawY(0));
 
     // Ensure that the x and y values are in the window's coordinate space.
     // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
     // the logical display space. This will be the origin of the window space.
-    EXPECT_EQ(100, event.getX(0));
-    EXPECT_EQ(80, event.getY(0));
+    EXPECT_EQ(100, event->getX(0));
+    EXPECT_EQ(80, event->getY(0));
 }
 
 TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
@@ -6081,7 +6096,8 @@
               injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
             << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
     window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-    MotionEvent* event = monitor.consumeMotion();
+    std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
+    ASSERT_NE(nullptr, event);
     // Even though window has transform, gesture monitor must not.
     ASSERT_EQ(ui::Transform(), event->getTransform());
 }
@@ -6188,9 +6204,9 @@
     const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
     mDispatcher->notifyKey(keyArgs);
 
-    const KeyEvent& event = window->consumeKey();
-
-    std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(event);
+    std::unique_ptr<KeyEvent> event = window->consumeKey();
+    ASSERT_NE(event, nullptr);
+    std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
     ASSERT_NE(verified, nullptr);
     ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
 
@@ -6231,9 +6247,9 @@
                                ADISPLAY_ID_DEFAULT);
     mDispatcher->notifyMotion(motionArgs);
 
-    const MotionEvent& event = window->consumeMotionEvent();
-
-    std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(event);
+    std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
+    ASSERT_NE(nullptr, event);
+    std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
     ASSERT_NE(verified, nullptr);
     ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
 
@@ -6760,13 +6776,13 @@
                                                      ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
     mDispatcher->notifyMotion(notifyArgs);
 
-    const MotionEvent& leftEnter = left->consumeMotionEvent(
+    std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
             AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
                   WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
-
+    ASSERT_NE(nullptr, leftEnter);
     spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
                                   Not(WithEventId(notifyArgs.id)),
-                                  Not(WithEventId(leftEnter.getId())),
+                                  Not(WithEventId(leftEnter->getId())),
                                   WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
 
     // Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
@@ -6774,13 +6790,13 @@
                                     {PointF{150, 50}});
     mDispatcher->notifyMotion(notifyArgs);
 
-    const MotionEvent& leftExit = left->consumeMotionEvent(
+    std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
             AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
                   WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
-
+    ASSERT_NE(nullptr, leftExit);
     right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
                                     Not(WithEventId(notifyArgs.id)),
-                                    Not(WithEventId(leftExit.getId())),
+                                    Not(WithEventId(leftExit->getId())),
                                     WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
 
     spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
@@ -6811,8 +6827,9 @@
     }
 
     void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
-        const KeyEvent& event = mWindow->consumeKey(handled);
-        ASSERT_THAT(event, matcher);
+        std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
+        ASSERT_NE(nullptr, event);
+        ASSERT_THAT(*event, matcher);
     }
 };
 
@@ -7146,9 +7163,10 @@
     GTEST_SKIP() << "Flaky test (b/270393106)";
     sendAndConsumeKeyDown(/*deviceId=*/1);
     for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
-        const KeyEvent& repeatEvent = mWindow->consumeKey();
+        std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
+        ASSERT_NE(nullptr, repeatEvent);
         EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
-                  IdGenerator::getSource(repeatEvent.getId()));
+                  IdGenerator::getSource(repeatEvent->getId()));
     }
 }
 
@@ -7158,8 +7176,9 @@
 
     std::unordered_set<int32_t> idSet;
     for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
-        const KeyEvent& repeatEvent = mWindow->consumeKey();
-        int32_t id = repeatEvent.getId();
+        std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
+        ASSERT_NE(nullptr, repeatEvent);
+        int32_t id = repeatEvent->getId();
         EXPECT_EQ(idSet.end(), idSet.find(id));
         idSet.insert(id);
     }
@@ -7813,21 +7832,21 @@
     void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
                             const std::vector<PointF>& points) {
         const std::string name = window->getName();
-        const MotionEvent& motionEvent =
+        std::unique_ptr<MotionEvent> motionEvent =
                 window->consumeMotionEvent(WithMotionAction(expectedAction));
-
-        ASSERT_EQ(points.size(), motionEvent.getPointerCount());
+        ASSERT_NE(nullptr, motionEvent);
+        ASSERT_EQ(points.size(), motionEvent->getPointerCount());
 
         for (size_t i = 0; i < points.size(); i++) {
             float expectedX = points[i].x;
             float expectedY = points[i].y;
 
-            EXPECT_EQ(expectedX, motionEvent.getX(i))
+            EXPECT_EQ(expectedX, motionEvent->getX(i))
                     << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
-                    << ", got " << motionEvent.getX(i);
-            EXPECT_EQ(expectedY, motionEvent.getY(i))
+                    << ", got " << motionEvent->getX(i);
+            EXPECT_EQ(expectedY, motionEvent->getY(i))
                     << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
-                    << ", got " << motionEvent.getY(i);
+                    << ", got " << motionEvent->getY(i);
         }
     }
 
@@ -8115,7 +8134,7 @@
               injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                                WINDOW_LOCATION));
 
-    std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
+    const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
     mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
@@ -8131,7 +8150,7 @@
 TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
     // Inject a key, and don't respond - expect that ANR is called.
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
-    std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
+    const auto [sequenceNum, _] = mWindow->receiveEvent();
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
     mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
@@ -8291,7 +8310,7 @@
                                WINDOW_LOCATION));
     mWindow->consumeMotionDown();
 
-    std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN
+    const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
     mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
@@ -8446,9 +8465,9 @@
     mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
 
     tapOnWindow();
-    std::optional<uint32_t> downSequenceNum = mWindow->receiveEvent();
+    const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
     ASSERT_TRUE(downSequenceNum);
-    std::optional<uint32_t> upSequenceNum = mWindow->receiveEvent();
+    const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
     ASSERT_TRUE(upSequenceNum);
     // Don't finish the events yet, and send a key
     // Injection will "succeed" because we will eventually give up and send the key to the focused
@@ -8486,9 +8505,9 @@
     mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
 
     tapOnWindow();
-    std::optional<uint32_t> downSequenceNum = mWindow->receiveEvent();
+    const auto& [downSequenceNum, _] = mWindow->receiveEvent();
     ASSERT_TRUE(downSequenceNum);
-    std::optional<uint32_t> upSequenceNum = mWindow->receiveEvent();
+    const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
     ASSERT_TRUE(upSequenceNum);
     // Don't finish the events yet, and send a key
     mDispatcher->notifyKey(
@@ -8524,7 +8543,7 @@
                                       .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
                                       .build());
 
-    std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
+    const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(sequenceNum);
     const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
     mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
@@ -8653,7 +8672,7 @@
                                                          .x(FOCUSED_WINDOW_LOCATION.x)
                                                          .y(FOCUSED_WINDOW_LOCATION.y))
                                         .build()));
-    std::optional<uint32_t> unfocusedSequenceNum = mUnfocusedWindow->receiveEvent();
+    const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
     ASSERT_TRUE(unfocusedSequenceNum);
 
     const std::chrono::duration timeout =
@@ -8718,9 +8737,9 @@
     tapOnFocusedWindow();
     mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
     // Receive the events, but don't respond
-    std::optional<uint32_t> downEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_DOWN
+    const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
     ASSERT_TRUE(downEventSequenceNum);
-    std::optional<uint32_t> upEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_UP
+    const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
     ASSERT_TRUE(upEventSequenceNum);
     const std::chrono::duration timeout =
             mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -8798,9 +8817,9 @@
             {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
 
     tapOnUnfocusedWindow();
-    std::optional<uint32_t> downSequenceNum = mUnfocusedWindow->receiveEvent();
+    const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
     ASSERT_TRUE(downSequenceNum);
-    std::optional<uint32_t> upSequenceNum = mUnfocusedWindow->receiveEvent();
+    const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
     ASSERT_TRUE(upSequenceNum);
     // Don't finish the events yet, and send a key
     // Injection will succeed because we will eventually give up and send the key to the focused
@@ -8863,8 +8882,7 @@
     mFocusedWindow->consumeMotionDown();
     // Focused window may or may not receive ACTION_MOVE
     // But it should definitely receive ACTION_CANCEL due to the ANR
-    InputEvent* event;
-    std::optional<int32_t> moveOrCancelSequenceNum = mFocusedWindow->receiveEvent(&event);
+    const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
     ASSERT_TRUE(moveOrCancelSequenceNum);
     mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
     ASSERT_NE(nullptr, event);
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 45fab7e..8e9dfea 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -16,13 +16,6 @@
 
 #include "SensorDevice.h"
 
-#include "android/hardware/sensors/2.0/types.h"
-#include "android/hardware/sensors/2.1/types.h"
-#include "convertV2_1.h"
-
-#include "AidlSensorHalWrapper.h"
-#include "HidlSensorHalWrapper.h"
-
 #include <android-base/logging.h>
 #include <android/util/ProtoOutputStream.h>
 #include <com_android_frameworks_sensorservice_flags.h>
@@ -36,10 +29,16 @@
 
 #include <chrono>
 #include <cinttypes>
-#include <cstddef>
-#include <thread>
-#include <mutex>
 #include <condition_variable>
+#include <cstddef>
+#include <mutex>
+#include <thread>
+
+#include "AidlSensorHalWrapper.h"
+#include "HidlSensorHalWrapper.h"
+#include "android/hardware/sensors/2.0/types.h"
+#include "android/hardware/sensors/2.1/types.h"
+#include "convertV2_1.h"
 
 using namespace android::hardware::sensors;
 using android::util::ProtoOutputStream;
@@ -168,6 +167,9 @@
 
     mActivationCount.clear();
     mSensorList.clear();
+    if (sensorservice_flags::dynamic_sensor_hal_reconnect_handling()) {
+        mConnectedDynamicSensors.clear();
+    }
 
     if (mHalWrapper->connect(this)) {
         initializeSensorList();
@@ -342,6 +344,15 @@
     }
 }
 
+std::vector<int32_t> SensorDevice::getDynamicSensorHandles() {
+    std::vector<int32_t> sensorHandles;
+    std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+    for (auto& sensors : mConnectedDynamicSensors) {
+        sensorHandles.push_back(sensors.first);
+    }
+    return sensorHandles;
+}
+
 ssize_t SensorDevice::getSensorList(sensor_t const** list) {
     *list = &mSensorList[0];
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index f127c0f..52f7cf2 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -60,6 +60,8 @@
 
     ssize_t getSensorList(sensor_t const** list);
 
+    std::vector<int32_t> getDynamicSensorHandles();
+
     void handleDynamicSensorConnection(int handle, bool connected);
     status_t initCheck() const;
     int getHalDeviceVersion() const;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 85043c9..e1c43c6 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "SensorService.h"
+
 #include <aidl/android/hardware/sensors/ISensors.h>
 #include <android-base/strings.h>
 #include <android/content/pm/IPackageManagerNative.h>
@@ -22,20 +24,36 @@
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
 #include <binder/PermissionController.h>
+#include <com_android_frameworks_sensorservice_flags.h>
 #include <cutils/ashmem.h>
 #include <cutils/misc.h>
 #include <cutils/properties.h>
 #include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <hardware/sensors.h>
 #include <hardware_legacy/power.h>
+#include <inttypes.h>
 #include <log/log.h>
+#include <math.h>
 #include <openssl/digest.h>
 #include <openssl/hmac.h>
 #include <openssl/rand.h>
+#include <private/android_filesystem_config.h>
+#include <sched.h>
 #include <sensor/SensorEventQueue.h>
 #include <sensorprivacy/SensorPrivacyManager.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 #include <utils/SystemClock.h>
 
+#include <condition_variable>
+#include <ctime>
+#include <future>
+#include <mutex>
+#include <string>
+
 #include "BatteryService.h"
 #include "CorrectedGyroSensor.h"
 #include "GravitySensor.h"
@@ -43,35 +61,17 @@
 #include "LinearAccelerationSensor.h"
 #include "OrientationSensor.h"
 #include "RotationVectorSensor.h"
-#include "SensorFusion.h"
-#include "SensorInterface.h"
-
-#include "SensorService.h"
 #include "SensorDirectConnection.h"
 #include "SensorEventAckReceiver.h"
 #include "SensorEventConnection.h"
+#include "SensorFusion.h"
+#include "SensorInterface.h"
 #include "SensorRecord.h"
 #include "SensorRegistrationInfo.h"
 #include "SensorServiceUtils.h"
 
-#include <inttypes.h>
-#include <math.h>
-#include <sched.h>
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <condition_variable>
-#include <ctime>
-#include <future>
-#include <mutex>
-#include <string>
-
-#include <private/android_filesystem_config.h>
-
 using namespace std::chrono_literals;
+namespace sensorservice_flags = com::android::frameworks::sensorservice::flags;
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -335,6 +335,11 @@
                     case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
                         hasGyroUncalibrated = true;
                         break;
+                    case SENSOR_TYPE_DYNAMIC_SENSOR_META:
+                        if (sensorservice_flags::dynamic_sensor_hal_reconnect_handling()) {
+                            mDynamicMetaSensorHandle = list[i].handle;
+                        }
+                      break;
                     case SENSOR_TYPE_GRAVITY:
                     case SENSOR_TYPE_LINEAR_ACCELERATION:
                     case SENSOR_TYPE_ROTATION_VECTOR:
@@ -1055,6 +1060,68 @@
    }
 }
 
+void SensorService::sendEventsToAllClients(
+    const std::vector<sp<SensorEventConnection>>& activeConnections,
+    ssize_t count) {
+   // Send our events to clients. Check the state of wake lock for each client
+   // and release the lock if none of the clients need it.
+   bool needsWakeLock = false;
+   for (const sp<SensorEventConnection>& connection : activeConnections) {
+       connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
+                              mMapFlushEventsToConnections);
+       needsWakeLock |= connection->needsWakeLock();
+       // If the connection has one-shot sensors, it may be cleaned up after
+       // first trigger. Early check for one-shot sensors.
+       if (connection->hasOneShotSensors()) {
+           cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
+       }
+   }
+
+   if (mWakeLockAcquired && !needsWakeLock) {
+        setWakeLockAcquiredLocked(false);
+   }
+}
+
+void SensorService::disconnectDynamicSensor(
+    int handle,
+    const std::vector<sp<SensorEventConnection>>& activeConnections) {
+   ALOGI("Dynamic sensor handle 0x%x disconnected", handle);
+   SensorDevice::getInstance().handleDynamicSensorConnection(
+       handle, false /*connected*/);
+   if (!unregisterDynamicSensorLocked(handle)) {
+        ALOGE("Dynamic sensor release error.");
+   }
+   for (const sp<SensorEventConnection>& connection : activeConnections) {
+        connection->removeSensor(handle);
+   }
+}
+
+void SensorService::handleDeviceReconnection(SensorDevice& device) {
+    if (sensorservice_flags::dynamic_sensor_hal_reconnect_handling()) {
+        const std::vector<sp<SensorEventConnection>> activeConnections =
+                mConnectionHolder.lock(mLock).getActiveConnections();
+
+        for (int32_t handle : device.getDynamicSensorHandles()) {
+            if (mDynamicMetaSensorHandle.has_value()) {
+                // Sending one event at a time to prevent the number of handle is more than the
+                // buffer can hold.
+                mSensorEventBuffer[0].type = SENSOR_TYPE_DYNAMIC_SENSOR_META;
+                mSensorEventBuffer[0].sensor = *mDynamicMetaSensorHandle;
+                mSensorEventBuffer[0].dynamic_sensor_meta.connected = false;
+                mSensorEventBuffer[0].dynamic_sensor_meta.handle = handle;
+                mMapFlushEventsToConnections[0] = nullptr;
+
+                disconnectDynamicSensor(handle, activeConnections);
+                sendEventsToAllClients(activeConnections, 1);
+            } else {
+                ALOGE("Failed to find mDynamicMetaSensorHandle during init.");
+                break;
+            }
+        }
+    }
+    device.reconnect();
+}
+
 bool SensorService::threadLoop() {
     ALOGD("nuSensorService thread starting...");
 
@@ -1071,8 +1138,8 @@
     do {
         ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
         if (count < 0) {
-            if(count == DEAD_OBJECT && device.isReconnecting()) {
-                device.reconnect();
+            if (count == DEAD_OBJECT && device.isReconnecting()) {
+                handleDeviceReconnection(device);
                 continue;
             } else {
                 ALOGE("sensor poll failed (%s)", strerror(-count));
@@ -1176,7 +1243,6 @@
                     rec->removeFirstPendingFlushConnection();
                 }
             }
-
             // handle dynamic sensor meta events, process registration and unregistration of dynamic
             // sensor based on content of event.
             if (mSensorEventBuffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
@@ -1206,37 +1272,14 @@
                     }
                 } else {
                     int handle = mSensorEventBuffer[i].dynamic_sensor_meta.handle;
-                    ALOGI("Dynamic sensor handle 0x%x disconnected", handle);
-
-                    device.handleDynamicSensorConnection(handle, false /*connected*/);
-                    if (!unregisterDynamicSensorLocked(handle)) {
-                        ALOGE("Dynamic sensor release error.");
-                    }
-
-                    for (const sp<SensorEventConnection>& connection : activeConnections) {
-                        connection->removeSensor(handle);
-                    }
+                    disconnectDynamicSensor(handle, activeConnections);
                 }
             }
         }
 
         // Send our events to clients. Check the state of wake lock for each client and release the
         // lock if none of the clients need it.
-        bool needsWakeLock = false;
-        for (const sp<SensorEventConnection>& connection : activeConnections) {
-            connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
-                                   mMapFlushEventsToConnections);
-            needsWakeLock |= connection->needsWakeLock();
-            // If the connection has one-shot sensors, it may be cleaned up after first trigger.
-            // Early check for one-shot sensors.
-            if (connection->hasOneShotSensors()) {
-                cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
-            }
-        }
-
-        if (mWakeLockAcquired && !needsWakeLock) {
-            setWakeLockAcquiredLocked(false);
-        }
+        sendEventsToAllClients(activeConnections, count);
     } while (!Thread::exitPending());
 
     ALOGW("Exiting SensorService::threadLoop => aborting...");
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b643f6b..ad10e7a 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -17,9 +17,6 @@
 #ifndef ANDROID_SENSOR_SERVICE_H
 #define ANDROID_SENSOR_SERVICE_H
 
-#include "SensorList.h"
-#include "RecentEventLogger.h"
-
 #include <android-base/macros.h>
 #include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
@@ -27,11 +24,11 @@
 #include <cutils/compiler.h>
 #include <cutils/multiuser.h>
 #include <private/android_filesystem_config.h>
-#include <sensor/ISensorServer.h>
 #include <sensor/ISensorEventConnection.h>
+#include <sensor/ISensorServer.h>
 #include <sensor/Sensor.h>
-#include "android/hardware/BnSensorPrivacyListener.h"
-
+#include <stdint.h>
+#include <sys/types.h>
 #include <utils/AndroidThreads.h>
 #include <utils/KeyedVector.h>
 #include <utils/Looper.h>
@@ -40,8 +37,6 @@
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
-#include <stdint.h>
-#include <sys/types.h>
 #include <condition_variable>
 #include <mutex>
 #include <queue>
@@ -49,6 +44,10 @@
 #include <unordered_set>
 #include <vector>
 
+#include "RecentEventLogger.h"
+#include "SensorList.h"
+#include "android/hardware/BnSensorPrivacyListener.h"
+
 #if __clang__
 // Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable
 // without changing the API, so let's tell clang this is indeed intentional.
@@ -57,7 +56,7 @@
 
 // ---------------------------------------------------------------------------
 #define IGNORE_HARDWARE_FUSION  false
-#define DEBUG_CONNECTIONS   false
+#define DEBUG_CONNECTIONS false
 // Max size is 100 KB which is enough to accept a batch of about 1000 events.
 #define MAX_SOCKET_BUFFER_SIZE_BATCHED (100 * 1024)
 // For older HALs which don't support batching, use a smaller socket buffer size.
@@ -453,6 +452,11 @@
     // Send events from the event cache for this particular connection.
     void sendEventsFromCache(const sp<SensorEventConnection>& connection);
 
+    // Send all events in the buffer to all clients.
+    void sendEventsToAllClients(
+        const std::vector<sp<SensorEventConnection>>& activeConnections,
+        ssize_t count);
+
     // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
     // allowed to register for or call flush on sensors. Typically only cts test packages are
     // allowed.
@@ -516,6 +520,14 @@
 
     bool isInjectionMode(int mode);
 
+    void handleDeviceReconnection(SensorDevice& device);
+
+    // Removes a connected dynamic sensor and send the corresponding event to
+    // all connections.
+    void disconnectDynamicSensor(
+        int handle,
+        const std::vector<sp<SensorEventConnection>>& activeConnections);
+
     static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
         return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
     }
@@ -583,6 +595,10 @@
     bool mLastReportedProxIsActive;
     // Listeners subscribed to receive updates on the proximity sensor active state.
     std::vector<sp<ProximityActiveListener>> mProximityActiveListeners;
+
+    // Stores the handle of the dynamic_meta sensor to send clean up event once
+    // HAL crashes.
+    std::optional<int> mDynamicMetaSensorHandle;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31d120d..fe5b159 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -492,14 +492,6 @@
     mSupportsBlur = supportsBlurs;
     ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported.");
 
-    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);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b23b519..6ae05d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1212,12 +1212,6 @@
     float mGlobalSaturationFactor = 1.0f;
     mat4 mClientColorMatrix;
 
-    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;
     bool mLayersAdded = false;
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 2f2895c..c01465b 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <functional>
 #include <mutex>
 #include <optional>
 #include <string>
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6b3c379..867fc45 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1369,197 +1369,221 @@
     const VkPhysicalDevice& pdev = GetData(device).driver_physical_device;
     const InstanceData& instance_data = GetData(pdev);
     const InstanceDriverTable& instance_dispatch = instance_data.driver;
-    if (!instance_dispatch.GetPhysicalDeviceImageFormatProperties2 &&
-            !instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
-        uint64_t native_usage = 0;
-        void* usage_info_pNext = nullptr;
-        VkResult result;
+    if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 ||
+            instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
+        // Look through the create_info pNext chain passed to createSwapchainKHR
+        // for an image compression control struct.
+        // if one is found AND the appropriate extensions are enabled, create a
+        // VkImageCompressionControlEXT structure to pass on to
+        // GetPhysicalDeviceImageFormatProperties2
+        void* compression_control_pNext = nullptr;
         VkImageCompressionControlEXT image_compression = {};
-        const auto& dispatch = GetData(device).driver;
-        if (dispatch.GetSwapchainGrallocUsage4ANDROID) {
-            ATRACE_BEGIN("GetSwapchainGrallocUsage4ANDROID");
-            VkGrallocUsageInfo2ANDROID gralloc_usage_info = {};
-            gralloc_usage_info.sType =
-                VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_2_ANDROID;
-            gralloc_usage_info.format = create_info->imageFormat;
-            gralloc_usage_info.imageUsage = create_info->imageUsage;
-            gralloc_usage_info.swapchainImageUsage = swapchain_image_usage;
-
-            // Look through the pNext chain for an image compression control struct
-            // if one is found AND the appropriate extensions are enabled,
-            // append it to be the gralloc usage pNext chain
-            const VkSwapchainCreateInfoKHR* create_infos = create_info;
-            while (create_infos->pNext) {
-                create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
-                    create_infos->pNext);
-                switch (create_infos->sType) {
-                    case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
-                        const VkImageCompressionControlEXT* compression_infos =
-                            reinterpret_cast<const VkImageCompressionControlEXT*>(
-                                create_infos);
-                        image_compression = *compression_infos;
-                        image_compression.pNext = nullptr;
-                        usage_info_pNext = &image_compression;
-                    } break;
-
-                    default:
-                        // Ignore all other info structs
-                        break;
-                }
+        const VkSwapchainCreateInfoKHR* create_infos = create_info;
+        while (create_infos->pNext) {
+            create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext);
+            switch (create_infos->sType) {
+                case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+                    const VkImageCompressionControlEXT* compression_infos =
+                        reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos);
+                    image_compression = *compression_infos;
+                    image_compression.pNext = nullptr;
+                    compression_control_pNext = &image_compression;
+                } break;
+                default:
+                    // Ignore all other info structs
+                    break;
             }
-            gralloc_usage_info.pNext = usage_info_pNext;
-
-            result = dispatch.GetSwapchainGrallocUsage4ANDROID(
-                device, &gralloc_usage_info, &native_usage);
-            ATRACE_END();
-            if (result != VK_SUCCESS) {
-                ALOGE("vkGetSwapchainGrallocUsage4ANDROID failed: %d", result);
-                return VK_ERROR_SURFACE_LOST_KHR;
-            }
-        } else if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
-            ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
-            VkGrallocUsageInfoANDROID gralloc_usage_info = {};
-            gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
-            gralloc_usage_info.format = create_info->imageFormat;
-            gralloc_usage_info.imageUsage = create_info->imageUsage;
-
-            // Look through the pNext chain for an image compression control struct
-            // if one is found AND the appropriate extensions are enabled,
-            // append it to be the gralloc usage pNext chain
-            const VkSwapchainCreateInfoKHR* create_infos = create_info;
-            while (create_infos->pNext) {
-                create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
-                    create_infos->pNext);
-                switch (create_infos->sType) {
-                    case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
-                        const VkImageCompressionControlEXT* compression_infos =
-                            reinterpret_cast<const VkImageCompressionControlEXT*>(
-                                create_infos);
-                        image_compression = *compression_infos;
-                        image_compression.pNext = nullptr;
-                        usage_info_pNext = &image_compression;
-                    } break;
-
-                    default:
-                        // Ignore all other info structs
-                        break;
-                }
-            }
-            gralloc_usage_info.pNext = usage_info_pNext;
-
-            result = dispatch.GetSwapchainGrallocUsage3ANDROID(
-                device, &gralloc_usage_info, &native_usage);
-            ATRACE_END();
-            if (result != VK_SUCCESS) {
-                ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
-                return VK_ERROR_SURFACE_LOST_KHR;
-            }
-        } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
-            uint64_t consumer_usage, producer_usage;
-            ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
-            result = dispatch.GetSwapchainGrallocUsage2ANDROID(
-                device, create_info->imageFormat, create_info->imageUsage,
-                swapchain_image_usage, &consumer_usage, &producer_usage);
-            ATRACE_END();
-            if (result != VK_SUCCESS) {
-                ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
-                return VK_ERROR_SURFACE_LOST_KHR;
-            }
-            native_usage =
-                convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
-        } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
-            ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
-            int32_t legacy_usage = 0;
-            result = dispatch.GetSwapchainGrallocUsageANDROID(
-                device, create_info->imageFormat, create_info->imageUsage,
-                &legacy_usage);
-            ATRACE_END();
-            if (result != VK_SUCCESS) {
-                ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
-                return VK_ERROR_SURFACE_LOST_KHR;
-            }
-            native_usage = static_cast<uint64_t>(legacy_usage);
         }
-        *producer_usage = native_usage;
 
-        return VK_SUCCESS;
+        // call GetPhysicalDeviceImageFormatProperties2KHR
+        VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
+            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
+            .pNext = compression_control_pNext,
+            .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
+        };
+
+        // AHB does not have an sRGB format so we can't pass it to GPDIFP
+        // We need to convert the format to unorm if it is srgb
+        VkFormat format = create_info->imageFormat;
+        if (format == VK_FORMAT_R8G8B8A8_SRGB) {
+            format = VK_FORMAT_R8G8B8A8_UNORM;
+        }
+
+        VkPhysicalDeviceImageFormatInfo2 image_format_info = {
+            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
+            .pNext = &external_image_format_info,
+            .format = format,
+            .type = VK_IMAGE_TYPE_2D,
+            .tiling = VK_IMAGE_TILING_OPTIMAL,
+            .usage = create_info->imageUsage,
+            .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
+        };
+
+        VkAndroidHardwareBufferUsageANDROID ahb_usage;
+        ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
+        ahb_usage.pNext = nullptr;
+
+        VkImageFormatProperties2 image_format_properties;
+        image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+        image_format_properties.pNext = &ahb_usage;
+
+        if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2) {
+            VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2(
+                pdev, &image_format_info, &image_format_properties);
+            if (result != VK_SUCCESS) {
+                ALOGE("VkGetPhysicalDeviceImageFormatProperties2 for AHB usage failed: %d", result);
+                return VK_ERROR_SURFACE_LOST_KHR;
+            }
+        }
+        else {
+            VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR(
+                pdev, &image_format_info,
+                &image_format_properties);
+            if (result != VK_SUCCESS) {
+                ALOGE("VkGetPhysicalDeviceImageFormatProperties2KHR for AHB usage failed: %d",
+                    result);
+                return VK_ERROR_SURFACE_LOST_KHR;
+            }
+        }
+
+        // Determine if USAGE_FRONT_BUFFER is needed.
+        // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when
+        // querying for producer_usage. So androidHardwareBufferUsage will not
+        // contain USAGE_FRONT_BUFFER. We need to manually check for usage here.
+        if (!(swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) {
+            *producer_usage = ahb_usage.androidHardwareBufferUsage;
+            return VK_SUCCESS;
+        }
+
+        // Check if USAGE_FRONT_BUFFER is supported for this swapchain
+        AHardwareBuffer_Desc ahb_desc = {
+            .width = create_info->imageExtent.width,
+            .height = create_info->imageExtent.height,
+            .layers = create_info->imageArrayLayers,
+            .format = create_info->imageFormat,
+            .usage = ahb_usage.androidHardwareBufferUsage | AHARDWAREBUFFER_USAGE_FRONT_BUFFER,
+            .stride = 0, // stride is always ignored when calling isSupported()
+        };
+
+        // If FRONT_BUFFER is not supported,
+        // then we need to call GetSwapchainGrallocUsageXAndroid below
+        if (AHardwareBuffer_isSupported(&ahb_desc)) {
+            *producer_usage = ahb_usage.androidHardwareBufferUsage;
+            *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
+            return VK_SUCCESS;
+        }
     }
 
-    // Look through the create_info pNext chain passed to createSwapchainKHR
-    // for an image compression control struct.
-    // if one is found AND the appropriate extensions are enabled, create a
-    // VkImageCompressionControlEXT structure to pass on to GetPhysicalDeviceImageFormatProperties2
-    void* compression_control_pNext = nullptr;
+    uint64_t native_usage = 0;
+    void* usage_info_pNext = nullptr;
+    VkResult result;
     VkImageCompressionControlEXT image_compression = {};
-    const VkSwapchainCreateInfoKHR* create_infos = create_info;
-    while (create_infos->pNext) {
-        create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext);
-        switch (create_infos->sType) {
-            case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
-                const VkImageCompressionControlEXT* compression_infos =
-                    reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos);
-                image_compression = *compression_infos;
-                image_compression.pNext = nullptr;
-                compression_control_pNext = &image_compression;
-            } break;
-            default:
-                // Ignore all other info structs
-                break;
+    const auto& dispatch = GetData(device).driver;
+    if (dispatch.GetSwapchainGrallocUsage4ANDROID) {
+        ATRACE_BEGIN("GetSwapchainGrallocUsage4ANDROID");
+        VkGrallocUsageInfo2ANDROID gralloc_usage_info = {};
+        gralloc_usage_info.sType =
+            VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_2_ANDROID;
+        gralloc_usage_info.format = create_info->imageFormat;
+        gralloc_usage_info.imageUsage = create_info->imageUsage;
+        gralloc_usage_info.swapchainImageUsage = swapchain_image_usage;
+
+        // Look through the pNext chain for an image compression control struct
+        // if one is found AND the appropriate extensions are enabled,
+        // append it to be the gralloc usage pNext chain
+        const VkSwapchainCreateInfoKHR* create_infos = create_info;
+        while (create_infos->pNext) {
+            create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+                create_infos->pNext);
+            switch (create_infos->sType) {
+                case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+                    const VkImageCompressionControlEXT* compression_infos =
+                        reinterpret_cast<const VkImageCompressionControlEXT*>(
+                            create_infos);
+                    image_compression = *compression_infos;
+                    image_compression.pNext = nullptr;
+                    usage_info_pNext = &image_compression;
+                } break;
+
+                default:
+                    // Ignore all other info structs
+                    break;
+            }
         }
-    }
+        gralloc_usage_info.pNext = usage_info_pNext;
 
-    // call GetPhysicalDeviceImageFormatProperties2KHR
-    VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
-        .pNext = compression_control_pNext,
-        .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
-    };
-
-    // AHB does not have an sRGB format so we can't pass it to GPDIFP
-    // We need to convert the format to unorm if it is srgb
-    VkFormat format = create_info->imageFormat;
-    if (format == VK_FORMAT_R8G8B8A8_SRGB) {
-        format = VK_FORMAT_R8G8B8A8_UNORM;
-    }
-
-    VkPhysicalDeviceImageFormatInfo2 image_format_info = {
-        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
-        .pNext = &external_image_format_info,
-        .format = format,
-        .type = VK_IMAGE_TYPE_2D,
-        .tiling = VK_IMAGE_TILING_OPTIMAL,
-        .usage = create_info->imageUsage,
-        .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
-    };
-
-    VkAndroidHardwareBufferUsageANDROID ahb_usage;
-    ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
-    ahb_usage.pNext = nullptr;
-
-    VkImageFormatProperties2 image_format_properties;
-    image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
-    image_format_properties.pNext = &ahb_usage;
-
-    if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2) {
-        VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2(
-            pdev, &image_format_info, &image_format_properties);
+        result = dispatch.GetSwapchainGrallocUsage4ANDROID(
+            device, &gralloc_usage_info, &native_usage);
+        ATRACE_END();
         if (result != VK_SUCCESS) {
-            ALOGE("VkGetPhysicalDeviceImageFormatProperties2 for AHB usage failed: %d", result);
+            ALOGE("vkGetSwapchainGrallocUsage4ANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;
         }
-    }
-    else {
-        VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR(
-            pdev, &image_format_info,
-            &image_format_properties);
+    } else if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
+        ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
+        VkGrallocUsageInfoANDROID gralloc_usage_info = {};
+        gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
+        gralloc_usage_info.format = create_info->imageFormat;
+        gralloc_usage_info.imageUsage = create_info->imageUsage;
+
+        // Look through the pNext chain for an image compression control struct
+        // if one is found AND the appropriate extensions are enabled,
+        // append it to be the gralloc usage pNext chain
+        const VkSwapchainCreateInfoKHR* create_infos = create_info;
+        while (create_infos->pNext) {
+            create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+                create_infos->pNext);
+            switch (create_infos->sType) {
+                case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+                    const VkImageCompressionControlEXT* compression_infos =
+                        reinterpret_cast<const VkImageCompressionControlEXT*>(
+                            create_infos);
+                    image_compression = *compression_infos;
+                    image_compression.pNext = nullptr;
+                    usage_info_pNext = &image_compression;
+                } break;
+
+                default:
+                    // Ignore all other info structs
+                    break;
+            }
+        }
+        gralloc_usage_info.pNext = usage_info_pNext;
+
+        result = dispatch.GetSwapchainGrallocUsage3ANDROID(
+            device, &gralloc_usage_info, &native_usage);
+        ATRACE_END();
         if (result != VK_SUCCESS) {
-            ALOGE("VkGetPhysicalDeviceImageFormatProperties2KHR for AHB usage failed: %d",
-                result);
+            ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
             return VK_ERROR_SURFACE_LOST_KHR;
         }
+    } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+        uint64_t consumer_usage, producer_usage;
+        ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
+        result = dispatch.GetSwapchainGrallocUsage2ANDROID(
+            device, create_info->imageFormat, create_info->imageUsage,
+            swapchain_image_usage, &consumer_usage, &producer_usage);
+        ATRACE_END();
+        if (result != VK_SUCCESS) {
+            ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        native_usage =
+            convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
+    } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
+        ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
+        int32_t legacy_usage = 0;
+        result = dispatch.GetSwapchainGrallocUsageANDROID(
+            device, create_info->imageFormat, create_info->imageUsage,
+            &legacy_usage);
+        ATRACE_END();
+        if (result != VK_SUCCESS) {
+            ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
+        native_usage = static_cast<uint64_t>(legacy_usage);
     }
-
-    *producer_usage = ahb_usage.androidHardwareBufferUsage;
+    *producer_usage = native_usage;
 
     return VK_SUCCESS;
 }