Merge "Add Android keycodes for stylus buttons"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6dea91b..0b69829 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -233,6 +233,7 @@
 // task and the log title of the duration report.
 static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
 static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
+static const std::string DUMP_NETSTATS_PROTO_TASK = "DUMP NETSTATS PROTO";
 static const std::string DUMP_HALS_TASK = "DUMP HALS";
 static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
 static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
@@ -1038,6 +1039,26 @@
     }
 }
 
+static void DumpNetstatsProto() {
+    const std::string path = ds.bugreport_internal_dir_ + "/tmp_netstats_proto";
+    auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
+                O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+    if (fd < 0) {
+        MYLOGE("Could not open %s to dump netstats proto.\n", path.c_str());
+        return;
+    }
+    RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"},
+            CommandOptions::WithTimeout(120).Build());
+    bool empty = 0 == lseek(fd, 0, SEEK_END);
+    if (!empty) {
+        ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt,
+                path);
+    } else {
+        unlink(path.c_str());
+    }
+}
+
 static void MaybeAddSystemTraceToZip() {
     // This function copies into the .zip the system trace that was snapshotted
     // by the early call to MaybeSnapshotSystemTrace(), if any background
@@ -1571,7 +1592,8 @@
     DurationReporter duration_reporter("DUMPSTATE");
 
     // Enqueue slow functions into the thread pool, if the parallel run is enabled.
-    std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins;
+    std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins,
+            dump_netstats_report;
     if (ds.dump_pool_) {
         // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
         // drop root user. Restarts it with two threads for the parallel run.
@@ -1580,6 +1602,8 @@
         dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
         dump_incident_report = ds.dump_pool_->enqueueTask(
             DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+        dump_netstats_report = ds.dump_pool_->enqueueTask(
+            DUMP_NETSTATS_PROTO_TASK, &DumpNetstatsProto);
         dump_board = ds.dump_pool_->enqueueTaskWithFd(
             DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
         dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
@@ -1778,6 +1802,13 @@
     dump_frozen_cgroupfs();
 
     if (ds.dump_pool_) {
+        WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_netstats_report));
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_NETSTATS_PROTO_TASK,
+                DumpNetstatsProto);
+    }
+
+    if (ds.dump_pool_) {
         WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report));
     } else {
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2c8adc7..b1283eb 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -99,6 +99,8 @@
 
 static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
 static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";
+static constexpr const char* kMiscMirrorCePath = "/data_mirror/misc_ce";
+static constexpr const char* kMiscMirrorDePath = "/data_mirror/misc_de";
 
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
@@ -125,8 +127,6 @@
 
 namespace {
 
-constexpr const char* kDump = "android.permission.DUMP";
-
 static binder::Status ok() {
     return binder::Status::ok();
 }
@@ -150,19 +150,6 @@
     return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
 }
 
-binder::Status checkPermission(const char* permission) {
-    pid_t pid;
-    uid_t uid;
-
-    if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
-            reinterpret_cast<int32_t*>(&uid))) {
-        return ok();
-    } else {
-        return exception(binder::Status::EX_SECURITY,
-                StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
-    }
-}
-
 binder::Status checkUid(uid_t expectedUid) {
     uid_t uid = IPCThreadState::self()->getCallingUid();
     if (uid == expectedUid || uid == AID_ROOT) {
@@ -400,13 +387,7 @@
     return android::OK;
 }
 
-status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
-    const binder::Status dump_permission = checkPermission(kDump);
-    if (!dump_permission.isOk()) {
-        dprintf(fd, "%s\n", dump_permission.toString8().c_str());
-        return PERMISSION_DENIED;
-    }
-
+status_t InstalldNativeService::dump(int fd, const Vector<String16>& /* args */) {
     {
         std::lock_guard<std::recursive_mutex> lock(mMountsLock);
         dprintf(fd, "Storage mounts:\n");
@@ -3579,16 +3560,28 @@
 
     std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
     if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
-        return error("Failed to create CE mirror");
+        return error("Failed to create CE data mirror");
     }
 
     std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
     if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
-        return error("Failed to create DE mirror");
+        return error("Failed to create DE data mirror");
+    }
+
+    std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+    if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+        return error("Failed to create CE misc mirror");
+    }
+
+    std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
+    if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+        return error("Failed to create DE misc mirror");
     }
 
     auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
     auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+    auto miscCePath = StringPrintf("%s/misc_ce", create_data_path(uuid_).c_str());
+    auto miscDePath = StringPrintf("%s/misc_de", create_data_path(uuid_).c_str());
 
     if (access(cePath.c_str(), F_OK) != 0) {
         return error("Cannot access CE path: " + cePath);
@@ -3596,6 +3589,12 @@
     if (access(dePath.c_str(), F_OK) != 0) {
         return error("Cannot access DE path: " + dePath);
     }
+    if (access(miscCePath.c_str(), F_OK) != 0) {
+        return error("Cannot access misc CE path: " + cePath);
+    }
+    if (access(miscDePath.c_str(), F_OK) != 0) {
+        return error("Cannot access misc DE path: " + dePath);
+    }
 
     struct stat ceStat, mirrorCeStat;
     if (stat(cePath.c_str(), &ceStat) != 0) {
@@ -3623,6 +3622,21 @@
             MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
         return error("Failed to mount " + mirrorVolDePath);
     }
+
+    // Mount misc CE mirror
+    if (TEMP_FAILURE_RETRY(mount(miscCePath.c_str(), mirrorVolMiscCePath.c_str(), NULL,
+                                 MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+                                 nullptr)) == -1) {
+        return error("Failed to mount " + mirrorVolMiscCePath);
+    }
+
+    // Mount misc DE mirror
+    if (TEMP_FAILURE_RETRY(mount(miscDePath.c_str(), mirrorVolMiscDePath.c_str(), NULL,
+                                 MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+                                 nullptr)) == -1) {
+        return error("Failed to mount " + mirrorVolMiscDePath);
+    }
+
     return ok();
 }
 
@@ -3645,6 +3659,8 @@
 
     std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
     std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+    std::string mirrorMiscCeVolPath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+    std::string mirrorMiscDeVolPath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
 
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
@@ -3669,6 +3685,29 @@
     if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
         res = error("Failed to delete " + mirrorDeVolPath);
     }
+
+    // Unmount misc CE storage
+    if (TEMP_FAILURE_RETRY(umount(mirrorMiscCeVolPath.c_str())) != 0) {
+        if (errno != ENOENT) {
+            res = error(StringPrintf("Failed to umount %s %s", mirrorMiscCeVolPath.c_str(),
+                                     strerror(errno)));
+        }
+    }
+    if (delete_dir_contents_and_dir(mirrorMiscCeVolPath, true) != 0) {
+        res = error("Failed to delete " + mirrorMiscCeVolPath);
+    }
+
+    // Unmount misc DE storage
+    if (TEMP_FAILURE_RETRY(umount(mirrorMiscDeVolPath.c_str())) != 0) {
+        if (errno != ENOENT) {
+            res = error(StringPrintf("Failed to umount %s %s", mirrorMiscDeVolPath.c_str(),
+                                     strerror(errno)));
+        }
+    }
+    if (delete_dir_contents_and_dir(mirrorMiscDeVolPath, true) != 0) {
+        res = error("Failed to delete " + mirrorMiscDeVolPath);
+    }
+
     return res;
 }
 
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 6144f5b..4251f04 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -145,16 +145,12 @@
     inline int32_t getActivePointerId() const { return mActivePointerId; }
 
 private:
-    // The default velocity tracker strategy.
+    // All axes supported for velocity tracking, mapped to their default strategies.
     // Although other strategies are available for testing and comparison purposes,
-    // this is the strategy that applications will actually use.  Be very careful
+    // the default strategy is the one that applications will actually use.  Be very careful
     // when adjusting the default strategy because it can dramatically affect
     // (often in a bad way) the user experience.
-    // TODO(b/32830165): define default strategy per axis.
-    static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2;
-
-    // Set of all axes supported for velocity tracking.
-    static const std::set<int32_t> SUPPORTED_AXES;
+    static const std::map<int32_t, Strategy> DEFAULT_STRATEGY_BY_AXIS;
 
     // Axes specifying location on a 2D plane (i.e. X and Y).
     static const std::set<int32_t> PLANAR_AXES;
@@ -162,9 +158,17 @@
     nsecs_t mLastEventTime;
     BitSet32 mCurrentPointerIdBits;
     int32_t mActivePointerId;
-    std::map<int32_t /*axis*/, std::unique_ptr<VelocityTrackerStrategy>> mStrategies;
 
-    void configureStrategy(int32_t axis, const Strategy strategy);
+    // An override strategy passed in the constructor to be used for all axes.
+    // This strategy will apply to all axes, unless the default strategy is specified here.
+    // When default strategy is specified, then each axis will use a potentially different strategy
+    // based on a hardcoded mapping.
+    const Strategy mOverrideStrategy;
+    // Maps axes to their respective VelocityTrackerStrategy instances.
+    // Note that, only axes that have had MotionEvents (and not all supported axes) will be here.
+    std::map<int32_t /*axis*/, std::unique_ptr<VelocityTrackerStrategy>> mConfiguredStrategies;
+
+    void configureStrategy(int32_t axis);
 
     static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy);
 };
@@ -180,7 +184,6 @@
 public:
     virtual ~VelocityTrackerStrategy() { }
 
-    virtual void clear() = 0;
     virtual void clearPointers(BitSet32 idBits) = 0;
     virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
                              const std::vector<float>& positions) = 0;
@@ -212,7 +215,6 @@
     LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE);
     virtual ~LeastSquaresVelocityTrackerStrategy();
 
-    virtual void clear();
     virtual void clearPointers(BitSet32 idBits);
     void addMovement(nsecs_t eventTime, BitSet32 idBits,
                      const std::vector<float>& positions) override;
@@ -253,7 +255,6 @@
     IntegratingVelocityTrackerStrategy(uint32_t degree);
     ~IntegratingVelocityTrackerStrategy();
 
-    virtual void clear();
     virtual void clearPointers(BitSet32 idBits);
     void addMovement(nsecs_t eventTime, BitSet32 idBits,
                      const std::vector<float>& positions) override;
@@ -286,7 +287,6 @@
     LegacyVelocityTrackerStrategy();
     virtual ~LegacyVelocityTrackerStrategy();
 
-    virtual void clear();
     virtual void clearPointers(BitSet32 idBits);
     void addMovement(nsecs_t eventTime, BitSet32 idBits,
                      const std::vector<float>& positions) override;
@@ -319,7 +319,6 @@
     ImpulseVelocityTrackerStrategy();
     virtual ~ImpulseVelocityTrackerStrategy();
 
-    virtual void clear();
     virtual void clearPointers(BitSet32 idBits);
     void addMovement(nsecs_t eventTime, BitSet32 idBits,
                      const std::vector<float>& positions) override;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b50cfb3..bfcf39a 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1318,6 +1318,13 @@
                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                 if (error < NO_ERROR) reply.setError(error);
 
+                // b/238777741: clear buffer before we send the reply.
+                // Otherwise, there is a race where the client may
+                // receive the reply and send another transaction
+                // here and the space used by this transaction won't
+                // be freed for the client.
+                buffer.setDataSize(0);
+
                 constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
                 sendReply(reply, (tr.flags & kForwardReplyFlags));
             } else {
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c0a8d74..5db3eef 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "ServiceManager"
+#define LOG_TAG "ServiceManagerCppClient"
 
 #include <binder/IServiceManager.h>
 
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 5de08bd..6e1c8ac 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1161,8 +1161,7 @@
 // see ProcessState.cpp BINDER_VM_SIZE = 1MB.
 // This value is not exposed, but some code in the framework relies on being able to use
 // buffers near the cap size.
-// TODO(b/238777741): why do larger values, like 300K fail sometimes
-constexpr size_t kSizeBytesAlmostFull = 100'000;
+constexpr size_t kSizeBytesAlmostFull = 950'000;
 constexpr size_t kSizeBytesOverFull = 1'050'000;
 
 TEST_F(BinderLibTest, GargantuanVectorSent) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 751721e..a9d6b0e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -632,7 +632,7 @@
         mAnimation(other.mAnimation),
         mEarlyWakeupStart(other.mEarlyWakeupStart),
         mEarlyWakeupEnd(other.mEarlyWakeupEnd),
-        mContainsBuffer(other.mContainsBuffer),
+        mMayContainBuffer(other.mMayContainBuffer),
         mDesiredPresentTime(other.mDesiredPresentTime),
         mIsAutoTimestamp(other.mIsAutoTimestamp),
         mFrameTimelineInfo(other.mFrameTimelineInfo),
@@ -667,7 +667,6 @@
     const bool animation = parcel->readBool();
     const bool earlyWakeupStart = parcel->readBool();
     const bool earlyWakeupEnd = parcel->readBool();
-    const bool containsBuffer = parcel->readBool();
     const int64_t desiredPresentTime = parcel->readInt64();
     const bool isAutoTimestamp = parcel->readBool();
     FrameTimelineInfo frameTimelineInfo;
@@ -745,7 +744,6 @@
     mAnimation = animation;
     mEarlyWakeupStart = earlyWakeupStart;
     mEarlyWakeupEnd = earlyWakeupEnd;
-    mContainsBuffer = containsBuffer;
     mDesiredPresentTime = desiredPresentTime;
     mIsAutoTimestamp = isAutoTimestamp;
     mFrameTimelineInfo = frameTimelineInfo;
@@ -777,7 +775,6 @@
     parcel->writeBool(mAnimation);
     parcel->writeBool(mEarlyWakeupStart);
     parcel->writeBool(mEarlyWakeupEnd);
-    parcel->writeBool(mContainsBuffer);
     parcel->writeInt64(mDesiredPresentTime);
     parcel->writeBool(mIsAutoTimestamp);
     mFrameTimelineInfo.writeToParcel(parcel);
@@ -876,7 +873,7 @@
 
     mInputWindowCommands.merge(other.mInputWindowCommands);
 
-    mContainsBuffer |= other.mContainsBuffer;
+    mMayContainBuffer |= other.mMayContainBuffer;
     mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart;
     mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd;
     mApplyToken = other.mApplyToken;
@@ -892,7 +889,7 @@
     mDisplayStates.clear();
     mListenerCallbacks.clear();
     mInputWindowCommands.clear();
-    mContainsBuffer = false;
+    mMayContainBuffer = false;
     mForceSynchronous = 0;
     mTransactionNestCount = 0;
     mAnimation = false;
@@ -920,7 +917,7 @@
 }
 
 void SurfaceComposerClient::Transaction::cacheBuffers() {
-    if (!mContainsBuffer) {
+    if (!mMayContainBuffer) {
         return;
     }
 
@@ -1464,7 +1461,6 @@
     s->what &= ~layer_state_t::eBufferChanged;
     s->bufferData = nullptr;
 
-    mContainsBuffer = false;
     return bufferData;
 }
 
@@ -1495,7 +1491,6 @@
     if (buffer == nullptr) {
         s->what &= ~layer_state_t::eBufferChanged;
         s->bufferData = nullptr;
-        mContainsBuffer = false;
         return *this;
     }
 
@@ -1530,7 +1525,7 @@
                                        const std::vector<SurfaceControlStats>&) {},
                                     nullptr);
 
-    mContainsBuffer = true;
+    mMayContainBuffer = true;
     return *this;
 }
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8c47ebc..963cc09 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -409,8 +409,10 @@
         bool mEarlyWakeupStart = false;
         bool mEarlyWakeupEnd = false;
 
-        // Indicates that the Transaction contains a buffer that should be cached
-        bool mContainsBuffer = false;
+        // Indicates that the Transaction may contain buffers that should be cached. The reason this
+        // is only a guess is that buffers can be removed before cache is called. This is only a
+        // hint that at some point a buffer was added to this transaction before apply was called.
+        bool mMayContainBuffer = false;
 
         // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
         // to be presented. When it is not possible to present at exactly that time, it will be
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 155cb04..2b7483d 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -949,6 +949,8 @@
         out << ", actionButton=" << std::to_string(event.getActionButton());
     }
     const size_t pointerCount = event.getPointerCount();
+    LOG_ALWAYS_FATAL_IF(pointerCount > MAX_POINTERS, "Too many pointers : pointerCount = %zu",
+                        pointerCount);
     for (size_t i = 0; i < pointerCount; i++) {
         out << ", id[" << i << "]=" << event.getPointerId(i);
         float x = event.getX(i);
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 6f88a38..527a75b 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -125,39 +125,32 @@
 
 // --- VelocityTracker ---
 
-const std::set<int32_t> VelocityTracker::SUPPORTED_AXES = {AMOTION_EVENT_AXIS_X,
-                                                           AMOTION_EVENT_AXIS_Y};
+const std::map<int32_t, VelocityTracker::Strategy> VelocityTracker::DEFAULT_STRATEGY_BY_AXIS =
+        {{AMOTION_EVENT_AXIS_X, VelocityTracker::Strategy::LSQ2},
+         {AMOTION_EVENT_AXIS_Y, VelocityTracker::Strategy::LSQ2}};
 
 const std::set<int32_t> VelocityTracker::PLANAR_AXES = {AMOTION_EVENT_AXIS_X, AMOTION_EVENT_AXIS_Y};
 
 VelocityTracker::VelocityTracker(const Strategy strategy)
-      : mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
-    // Configure the strategy for each axis.
-    for (int32_t axis : SUPPORTED_AXES) {
-        configureStrategy(axis, strategy);
-    }
-}
+      : mLastEventTime(0),
+        mCurrentPointerIdBits(0),
+        mActivePointerId(-1),
+        mOverrideStrategy(strategy) {}
 
 VelocityTracker::~VelocityTracker() {
 }
 
-void VelocityTracker::configureStrategy(int32_t axis, const Strategy strategy) {
+void VelocityTracker::configureStrategy(int32_t axis) {
     std::unique_ptr<VelocityTrackerStrategy> createdStrategy;
-
-    if (strategy == VelocityTracker::Strategy::DEFAULT) {
-        createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
+    if (mOverrideStrategy != VelocityTracker::Strategy::DEFAULT) {
+        createdStrategy = createStrategy(mOverrideStrategy);
     } else {
-        createdStrategy = createStrategy(strategy);
+        createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY_BY_AXIS.at(axis));
     }
 
-    if (createdStrategy == nullptr) {
-        ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy);
-        createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
-        LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr,
-                            "Could not create the default velocity tracker strategy '%" PRId32 "'!",
-                            strategy);
-    }
-    mStrategies[axis] = std::move(createdStrategy);
+    LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr,
+                        "Could not create velocity tracker strategy for axis '%" PRId32 "'!", axis);
+    mConfiguredStrategies[axis] = std::move(createdStrategy);
 }
 
 std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy(
@@ -211,9 +204,7 @@
 void VelocityTracker::clear() {
     mCurrentPointerIdBits.clear();
     mActivePointerId = -1;
-    for (int32_t axis : SUPPORTED_AXES) {
-        mStrategies[axis]->clear();
-    }
+    mConfiguredStrategies.clear();
 }
 
 void VelocityTracker::clearPointers(BitSet32 idBits) {
@@ -224,8 +215,8 @@
         mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
     }
 
-    for (int32_t axis : SUPPORTED_AXES) {
-        mStrategies[axis]->clearPointers(idBits);
+    for (const auto& [_, strategy] : mConfiguredStrategies) {
+        strategy->clearPointers(idBits);
     }
 }
 
@@ -242,9 +233,7 @@
 
         // We have not received any movements for too long.  Assume that all pointers
         // have stopped.
-        for (const auto& [_, strategy] : mStrategies) {
-            strategy->clear();
-        }
+        mConfiguredStrategies.clear();
     }
     mLastEventTime = eventTime;
 
@@ -257,7 +246,10 @@
         LOG_ALWAYS_FATAL_IF(idBits.count() != positionValues.size(),
                             "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
                             idBits.count(), positionValues.size());
-        mStrategies[axis]->addMovement(eventTime, idBits, positionValues);
+        if (mConfiguredStrategies.find(axis) == mConfiguredStrategies.end()) {
+            configureStrategy(axis);
+        }
+        mConfiguredStrategies[axis]->addMovement(eventTime, idBits, positionValues);
     }
 
     if (DEBUG_VELOCITY) {
@@ -323,7 +315,7 @@
             // We have not received any movements for too long.  Assume that all pointers
             // have stopped.
             for (int32_t axis : PLANAR_AXES) {
-                mStrategies[axis]->clear();
+                mConfiguredStrategies.erase(axis);
             }
         }
         // These actions because they do not convey any new information about
@@ -385,7 +377,7 @@
 VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t units,
                                                                        float maxVelocity) {
     ComputedVelocity computedVelocity;
-    for (int32_t axis : SUPPORTED_AXES) {
+    for (const auto& [axis, _] : mConfiguredStrategies) {
         BitSet32 copyIdBits = BitSet32(mCurrentPointerIdBits);
         while (!copyIdBits.isEmpty()) {
             uint32_t id = copyIdBits.clearFirstMarkedBit();
@@ -401,28 +393,22 @@
 }
 
 bool VelocityTracker::getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const {
-    if (SUPPORTED_AXES.find(axis) == SUPPORTED_AXES.end()) {
+    const auto& it = mConfiguredStrategies.find(axis);
+    if (it == mConfiguredStrategies.end()) {
         return false;
     }
-    return mStrategies.at(axis)->getEstimator(id, outEstimator);
+    return it->second->getEstimator(id, outEstimator);
 }
 
 // --- LeastSquaresVelocityTrackerStrategy ---
 
-LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
-        uint32_t degree, Weighting weighting) :
-        mDegree(degree), mWeighting(weighting) {
-    clear();
-}
+LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree,
+                                                                         Weighting weighting)
+      : mDegree(degree), mWeighting(weighting), mIndex(0) {}
 
 LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {
 }
 
-void LeastSquaresVelocityTrackerStrategy::clear() {
-    mIndex = 0;
-    mMovements[0].idBits.clear();
-}
-
 void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
     BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
     mMovements[mIndex].idBits = remainingIdBits;
@@ -825,10 +811,6 @@
 IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
 }
 
-void IntegratingVelocityTrackerStrategy::clear() {
-    mPointerIdBits.clear();
-}
-
 void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
     mPointerIdBits.value &= ~idBits.value;
 }
@@ -920,18 +902,11 @@
 
 // --- LegacyVelocityTrackerStrategy ---
 
-LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
-    clear();
-}
+LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() : mIndex(0) {}
 
 LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() {
 }
 
-void LegacyVelocityTrackerStrategy::clear() {
-    mIndex = 0;
-    mMovements[0].idBits.clear();
-}
-
 void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
     BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
     mMovements[mIndex].idBits = remainingIdBits;
@@ -1029,18 +1004,11 @@
 
 // --- ImpulseVelocityTrackerStrategy ---
 
-ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() {
-    clear();
-}
+ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() : mIndex(0) {}
 
 ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
 }
 
-void ImpulseVelocityTrackerStrategy::clear() {
-    mIndex = 0;
-    mMovements[0].idBits.clear();
-}
-
 void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
     BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
     mMovements[mIndex].idBits = remainingIdBits;
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index f8e5052..0b7def3 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -308,6 +308,27 @@
     EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID));
 }
 
+TEST_F(VelocityTrackerTest, TestApiInteractionsWithNoMotionEvents) {
+    VelocityTracker vt(VelocityTracker::Strategy::DEFAULT);
+
+    EXPECT_FALSE(vt.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID));
+
+    VelocityTracker::Estimator estimator;
+    EXPECT_FALSE(vt.getEstimator(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID, &estimator));
+
+    VelocityTracker::ComputedVelocity computedVelocity = vt.getComputedVelocity(1000, 1000);
+    for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) {
+        EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id));
+        EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, id));
+    }
+
+    EXPECT_EQ(-1, vt.getActivePointerId());
+
+    // Make sure that the clearing functions execute without an issue.
+    vt.clearPointers(BitSet32(7U));
+    vt.clear();
+}
+
 TEST_F(VelocityTrackerTest, ThreePointsPositiveVelocityTest) {
     // Same coordinate is reported 2 times in a row
     // It is difficult to determine the correct answer here, but at least the direction
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 9d8b2df..777d02f 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -37,7 +37,6 @@
 #include <condition_variable>
 #include <fstream>
 
-#include "../gl/GLESRenderEngine.h"
 #include "../skia/SkiaGLRenderEngine.h"
 #include "../threaded/RenderEngineThreaded.h"
 
@@ -108,73 +107,9 @@
     virtual std::string name() = 0;
     virtual renderengine::RenderEngine::RenderEngineType type() = 0;
     virtual std::unique_ptr<renderengine::RenderEngine> createRenderEngine() = 0;
-    virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() {
-        return nullptr;
-    }
     virtual bool useColorManagement() const = 0;
 };
 
-class GLESRenderEngineFactory : public RenderEngineFactory {
-public:
-    std::string name() override { return "GLESRenderEngineFactory"; }
-
-    renderengine::RenderEngine::RenderEngineType type() {
-        return renderengine::RenderEngine::RenderEngineType::GLES;
-    }
-
-    std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
-        return createGLESRenderEngine();
-    }
-
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() {
-        renderengine::RenderEngineCreationArgs reCreationArgs =
-                renderengine::RenderEngineCreationArgs::Builder()
-                        .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
-                        .setImageCacheSize(1)
-                        .setUseColorManagerment(false)
-                        .setEnableProtectedContext(false)
-                        .setPrecacheToneMapperShaderOnly(false)
-                        .setSupportsBackgroundBlur(true)
-                        .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-                        .setRenderEngineType(type())
-                        .setUseColorManagerment(useColorManagement())
-                        .build();
-        return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
-    }
-
-    bool useColorManagement() const override { return false; }
-};
-
-class GLESCMRenderEngineFactory : public RenderEngineFactory {
-public:
-    std::string name() override { return "GLESCMRenderEngineFactory"; }
-
-    renderengine::RenderEngine::RenderEngineType type() {
-        return renderengine::RenderEngine::RenderEngineType::GLES;
-    }
-
-    std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
-        return createGLESRenderEngine();
-    }
-
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() override {
-        renderengine::RenderEngineCreationArgs reCreationArgs =
-                renderengine::RenderEngineCreationArgs::Builder()
-                        .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
-                        .setImageCacheSize(1)
-                        .setEnableProtectedContext(false)
-                        .setPrecacheToneMapperShaderOnly(false)
-                        .setSupportsBackgroundBlur(true)
-                        .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-                        .setRenderEngineType(type())
-                        .setUseColorManagerment(useColorManagement())
-                        .build();
-        return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
-    }
-
-    bool useColorManagement() const override { return true; }
-};
-
 class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
 public:
     std::string name() override { return "SkiaGLRenderEngineFactory"; }
@@ -313,9 +248,6 @@
         }
         for (uint32_t texName : mTexNames) {
             mRE->deleteTextures(1, &texName);
-            if (mGLESRE != nullptr) {
-                EXPECT_FALSE(mGLESRE->isTextureNameKnownForTesting(texName));
-            }
         }
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
@@ -537,10 +469,6 @@
 
         auto fence = result.value();
         fence->waitForever(LOG_TAG);
-
-        if (layers.size() > 0 && mGLESRE != nullptr) {
-            ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
-        }
     }
 
     void drawEmptyLayers() {
@@ -663,26 +591,13 @@
 
     std::unique_ptr<renderengine::RenderEngine> mRE;
     std::shared_ptr<renderengine::ExternalTexture> mBuffer;
-    // GLESRenderEngine for testing GLES-specific behavior.
-    // Owened by mRE, but this is downcasted.
-    renderengine::gl::GLESRenderEngine* mGLESRE = nullptr;
 
     std::vector<uint32_t> mTexNames;
 };
 
 void RenderEngineTest::initializeRenderEngine() {
     const auto& renderEngineFactory = GetParam();
-    if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        // Only GLESRenderEngine exposes test-only methods. Provide a pointer to the
-        // GLESRenderEngine if we're using it so that we don't need to dynamic_cast
-        // every time.
-        std::unique_ptr<renderengine::gl::GLESRenderEngine> renderEngine =
-                renderEngineFactory->createGLESRenderEngine();
-        mGLESRE = renderEngine.get();
-        mRE = std::move(renderEngine);
-    } else {
-        mRE = renderEngineFactory->createRenderEngine();
-    }
+    mRE = renderEngineFactory->createRenderEngine();
     mBuffer = allocateDefaultBuffer();
 }
 
@@ -1003,9 +918,9 @@
     std::vector<renderengine::LayerSettings> layers;
 
     renderengine::LayerSettings layer;
-    layer.sourceDataspace = sourceDataspace;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
     SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+    layer.sourceDataspace = sourceDataspace;
     layer.alpha = 1.0f;
 
     // construct a fake color matrix
@@ -1031,13 +946,13 @@
 template <typename SourceVariant>
 void RenderEngineTest::fillBufferColorTransformAndSourceDataspace() {
     unordered_map<ui::Dataspace, ubyte4> dataspaceToColorMap;
-    dataspaceToColorMap[ui::Dataspace::V0_BT709] = {172, 0, 0, 255};
-    dataspaceToColorMap[ui::Dataspace::BT2020] = {172, 0, 0, 255};
-    dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {172, 0, 0, 255};
+    dataspaceToColorMap[ui::Dataspace::V0_BT709] = {77, 0, 0, 255};
+    dataspaceToColorMap[ui::Dataspace::BT2020] = {101, 0, 0, 255};
+    dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {75, 0, 0, 255};
     ui::Dataspace customizedDataspace = static_cast<ui::Dataspace>(
             ui::Dataspace::STANDARD_BT709 | ui::Dataspace::TRANSFER_GAMMA2_2 |
             ui::Dataspace::RANGE_FULL);
-    dataspaceToColorMap[customizedDataspace] = {172, 0, 0, 255};
+    dataspaceToColorMap[customizedDataspace] = {61, 0, 0, 255};
     for (const auto& [sourceDataspace, color] : dataspaceToColorMap) {
         fillBufferWithColorTransformAndSourceDataspace<SourceVariant>(sourceDataspace);
         expectBufferColor(fullscreenRect(), color.r, color.g, color.b, color.a, 1);
@@ -1077,13 +992,13 @@
 template <typename SourceVariant>
 void RenderEngineTest::fillBufferColorTransformAndOutputDataspace() {
     unordered_map<ui::Dataspace, ubyte4> dataspaceToColorMap;
-    dataspaceToColorMap[ui::Dataspace::V0_BT709] = {202, 0, 0, 255};
-    dataspaceToColorMap[ui::Dataspace::BT2020] = {192, 0, 0, 255};
-    dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {202, 0, 0, 255};
+    dataspaceToColorMap[ui::Dataspace::V0_BT709] = {198, 0, 0, 255};
+    dataspaceToColorMap[ui::Dataspace::BT2020] = {187, 0, 0, 255};
+    dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {192, 0, 0, 255};
     ui::Dataspace customizedDataspace = static_cast<ui::Dataspace>(
             ui::Dataspace::STANDARD_BT709 | ui::Dataspace::TRANSFER_GAMMA2_6 |
             ui::Dataspace::RANGE_FULL);
-    dataspaceToColorMap[customizedDataspace] = {202, 0, 0, 255};
+    dataspaceToColorMap[customizedDataspace] = {205, 0, 0, 255};
     for (const auto& [outputDataspace, color] : dataspaceToColorMap) {
         fillBufferWithColorTransformAndOutputDataspace<SourceVariant>(outputDataspace);
         expectBufferColor(fullscreenRect(), color.r, color.g, color.b, color.a, 1);
@@ -1599,9 +1514,7 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
-                         testing::Values(std::make_shared<GLESRenderEngineFactory>(),
-                                         std::make_shared<GLESCMRenderEngineFactory>(),
-                                         std::make_shared<SkiaGLESRenderEngineFactory>(),
+                         testing::Values(std::make_shared<SkiaGLESRenderEngineFactory>(),
                                          std::make_shared<SkiaGLESCMRenderEngineFactory>()));
 
 TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
@@ -1610,12 +1523,6 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) {
-    const auto& renderEngineFactory = GetParam();
-    if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        // GLES-specific test
-        return;
-    }
-
     initializeRenderEngine();
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1689,41 +1596,6 @@
     ASSERT_EQ(BAD_VALUE, result.error());
 }
 
-TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
-    const auto& renderEngineFactory = GetParam();
-
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        // GLES-specific test
-        return;
-    }
-
-    initializeRenderEngine();
-
-    renderengine::DisplaySettings settings;
-    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
-    settings.physicalDisplay = fullscreenRect();
-    settings.clip = fullscreenRect();
-
-    std::vector<renderengine::LayerSettings> layers;
-    renderengine::LayerSettings layer;
-    layer.geometry.boundaries = fullscreenRect().toFloatRect();
-    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
-    layer.alpha = 1.0;
-    layers.push_back(layer);
-
-    ftl::Future<FenceResult> future =
-            mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
-    ASSERT_TRUE(future.valid());
-    auto result = future.get();
-
-    ASSERT_TRUE(result.ok());
-    auto fence = result.value();
-    fence->waitForever(LOG_TAG);
-
-    ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
-    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
-}
-
 TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
     initializeRenderEngine();
     fillRedBuffer<ColorSourceVariant>();
@@ -1783,11 +1655,7 @@
     const auto& renderEngineFactory = GetParam();
     // skip for non color management
     if (!renderEngineFactory->useColorManagement()) {
-        return;
-    }
-    // skip for GLESRenderEngine
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
@@ -1798,11 +1666,7 @@
     const auto& renderEngineFactory = GetParam();
     // skip for non color management
     if (!renderEngineFactory->useColorManagement()) {
-        return;
-    }
-    // skip for GLESRenderEngine
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
@@ -1893,11 +1757,7 @@
     const auto& renderEngineFactory = GetParam();
     // skip for non color management
     if (!renderEngineFactory->useColorManagement()) {
-        return;
-    }
-    // skip for GLESRenderEngine
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
@@ -1908,11 +1768,7 @@
     const auto& renderEngineFactory = GetParam();
     // skip for non color management
     if (!renderEngineFactory->useColorManagement()) {
-        return;
-    }
-    // skip for GLESRenderEngine
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
@@ -2003,11 +1859,7 @@
     const auto& renderEngineFactory = GetParam();
     // skip for non color management
     if (!renderEngineFactory->useColorManagement()) {
-        return;
-    }
-    // skip for GLESRenderEngine
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
@@ -2018,11 +1870,7 @@
     const auto& renderEngineFactory = GetParam();
     // skip for non color management
     if (!renderEngineFactory->useColorManagement()) {
-        return;
-    }
-    // skip for GLESRenderEngine
-    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
@@ -2537,10 +2385,6 @@
 }
 
 TEST_P(RenderEngineTest, testDimming) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
-
     initializeRenderEngine();
 
     const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -2613,9 +2457,6 @@
 }
 
 TEST_P(RenderEngineTest, testDimming_inGammaSpace) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
     initializeRenderEngine();
 
     const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
@@ -2691,9 +2532,6 @@
 }
 
 TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
     initializeRenderEngine();
 
     const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
@@ -2754,9 +2592,6 @@
 }
 
 TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_deviceHandles) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
     initializeRenderEngine();
 
     const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
@@ -2819,9 +2654,6 @@
 
 TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
     initializeRenderEngine();
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
-    }
 
     const auto displayRect = Rect(2, 1);
     const renderengine::DisplaySettings display{
@@ -2927,10 +2759,6 @@
         GTEST_SKIP();
     }
 
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
-
     initializeRenderEngine();
 
     tonemap(
@@ -2948,10 +2776,6 @@
         GTEST_SKIP();
     }
 
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
-
     initializeRenderEngine();
 
     tonemap(
@@ -2965,10 +2789,6 @@
 }
 
 TEST_P(RenderEngineTest, r8_behaves_as_mask) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
-    }
-
     initializeRenderEngine();
 
     const auto r8Buffer = allocateR8Buffer(2, 1);
@@ -3026,10 +2846,6 @@
 }
 
 TEST_P(RenderEngineTest, r8_respects_color_transform) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
-    }
-
     initializeRenderEngine();
 
     const auto r8Buffer = allocateR8Buffer(2, 1);
@@ -3092,10 +2908,6 @@
 }
 
 TEST_P(RenderEngineTest, r8_respects_color_transform_when_device_handles) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
-    }
-
     initializeRenderEngine();
 
     const auto r8Buffer = allocateR8Buffer(2, 1);
@@ -3161,10 +2973,6 @@
 }
 
 TEST_P(RenderEngineTest, primeShaderCache) {
-    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        GTEST_SKIP();
-    }
-
     initializeRenderEngine();
 
     auto fut = mRE->primeCache();
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index f673a28..4a0f2ec 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -38,6 +38,7 @@
       "name": "CtsViewTestCases",
       "options": [
         {
+          "include-filter": "android.view.cts.input",
           "include-filter": "android.view.cts.MotionEventTest",
           "include-filter": "android.view.cts.PointerCaptureTest",
           "include-filter": "android.view.cts.VerifyInputEventTest"
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index d34ae49..d2ad407 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -74,11 +74,8 @@
 
 /**
  * Log debug messages about touch occlusion
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchOcclusion DEBUG" (requires
- * restart)
  */
-const bool DEBUG_TOUCH_OCCLUSION =
-        __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchOcclusion", ANDROID_LOG_INFO);
+constexpr bool DEBUG_TOUCH_OCCLUSION = true;
 
 /**
  * Log debug messages about the app switch latency optimization.
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 85dcf8f..4da846b 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -39,7 +39,7 @@
     return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
 }
 
-std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) const {
+std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
     auto it = mFocusRequestByDisplay.find(displayId);
     return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt;
 }
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index 8a6dfa4..6d11a77 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -62,7 +62,6 @@
     std::optional<FocusResolver::FocusChanges> setFocusedWindow(
             const android::gui::FocusRequest& request,
             const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
-    std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId) const;
 
     // Display has been removed from the system, clean up old references.
     void displayRemoved(int32_t displayId);
@@ -113,6 +112,7 @@
     std::optional<FocusResolver::FocusChanges> updateFocusedWindow(
             int32_t displayId, const std::string& reason, const sp<IBinder>& token,
             const std::string& tokenName = "");
+    std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId);
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b52e312..ff63a6f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -659,13 +659,6 @@
     if (focusedWindowHandle != nullptr) {
         return; // We now have a focused window. No need for ANR.
     }
-    std::optional<FocusRequest> pendingRequest =
-            mFocusResolver.getFocusRequest(mAwaitedApplicationDisplayId);
-    if (pendingRequest.has_value() && onAnrLocked(*pendingRequest)) {
-        // We don't have a focusable window but we know which window should have
-        // been focused. Blame that process in case it doesn't belong to the focused app.
-        return;
-    }
     onAnrLocked(mAwaitedFocusedApplication);
 }
 
@@ -2998,7 +2991,7 @@
         ATRACE_NAME(message.c_str());
     }
 
-    bool wasEmpty = connection->outboundQueue.empty();
+    const bool wasEmpty = connection->outboundQueue.empty();
 
     // Enqueue dispatch entries for the requested modes.
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
@@ -3681,6 +3674,8 @@
     target.inputChannel = connection->inputChannel;
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
+    const bool wasEmpty = connection->outboundQueue.empty();
+
     for (size_t i = 0; i < cancelationEvents.size(); i++) {
         std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]);
         switch (cancelationEventEntry->type) {
@@ -3715,7 +3710,10 @@
                                    InputTarget::FLAG_DISPATCH_AS_IS);
     }
 
-    startDispatchCycleLocked(currentTime, connection);
+    // If the outbound queue was previously empty, start the dispatch cycle going.
+    if (wasEmpty && !connection->outboundQueue.empty()) {
+        startDispatchCycleLocked(currentTime, connection);
+    }
 }
 
 void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
@@ -3747,6 +3745,7 @@
     target.inputChannel = connection->inputChannel;
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
+    const bool wasEmpty = connection->outboundQueue.empty();
     for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
         switch (downEventEntry->type) {
             case EventEntry::Type::MOTION: {
@@ -3773,7 +3772,10 @@
                                    InputTarget::FLAG_DISPATCH_AS_IS);
     }
 
-    startDispatchCycleLocked(downTime, connection);
+    // If the outbound queue was previously empty, start the dispatch cycle going.
+    if (wasEmpty && !connection->outboundQueue.empty()) {
+        startDispatchCycleLocked(downTime, connection);
+    }
 }
 
 std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
@@ -5855,25 +5857,6 @@
     postCommandLocked(std::move(command));
 }
 
-bool InputDispatcher::onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) {
-    if (pendingFocusRequest.token == nullptr) {
-        return false;
-    }
-
-    const std::string reason = android::base::StringPrintf("%s is not focusable.",
-                                                           pendingFocusRequest.windowName.c_str());
-    updateLastAnrStateLocked(pendingFocusRequest.windowName, reason);
-    sp<Connection> connection = getConnectionLocked(pendingFocusRequest.token);
-    if (connection != nullptr) {
-        processConnectionUnresponsiveLocked(*connection, std::move(reason));
-        // Stop waking up for events on this connection, it is already unresponsive
-        cancelEventsForAnrLocked(connection);
-    } else {
-        sendWindowUnresponsiveCommandLocked(pendingFocusRequest.token, std::nullopt, reason);
-    }
-    return true;
-}
-
 void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
     if (connection == nullptr) {
         LOG_ALWAYS_FATAL("Caller must check for nullness");
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d078b35..b5bbce8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -657,7 +657,6 @@
     void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
     void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
     void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
-    bool onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) REQUIRES(mLock);
     void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
                                   const std::string& reason) REQUIRES(mLock);
     void updateLastAnrStateLocked(const InputApplicationHandle& application,
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 4442459..cacb63c 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -113,6 +113,8 @@
     virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0;
     /* Get battery status of a particular input device. */
     virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0;
+    /* Get the device path for the battery of an input device. */
+    virtual std::optional<std::string> getBatteryDevicePath(int32_t deviceId) = 0;
 
     virtual std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) = 0;
 
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index ff0b9a5..c9d21dc 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1555,7 +1555,7 @@
         // the lock to prevent event processing from being blocked by this call.
         std::scoped_lock _l(mLock);
 
-        const auto infos = getBatteryInfoLocked(deviceId);
+        const auto& infos = getBatteryInfoLocked(deviceId);
         auto it = infos.find(batteryId);
         if (it == infos.end()) {
             return std::nullopt;
@@ -1596,7 +1596,7 @@
         // the lock to prevent event processing from being blocked by this call.
         std::scoped_lock _l(mLock);
 
-        const auto infos = getBatteryInfoLocked(deviceId);
+        const auto& infos = getBatteryInfoLocked(deviceId);
         auto it = infos.find(batteryId);
         if (it == infos.end()) {
             return std::nullopt;
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 4750d90..4c38ce8 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -721,7 +721,10 @@
 
     if (!eventHubId) return {};
     const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
-    if (batteryIds.empty()) return {};
+    if (batteryIds.empty()) {
+        ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId);
+        return {};
+    }
     return mEventHub->getBatteryCapacity(*eventHubId, batteryIds.front());
 }
 
@@ -741,10 +744,35 @@
 
     if (!eventHubId) return {};
     const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
-    if (batteryIds.empty()) return {};
+    if (batteryIds.empty()) {
+        ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId);
+        return {};
+    }
     return mEventHub->getBatteryStatus(*eventHubId, batteryIds.front());
 }
 
+std::optional<std::string> InputReader::getBatteryDevicePath(int32_t deviceId) {
+    std::scoped_lock _l(mLock);
+
+    InputDevice* device = findInputDeviceLocked(deviceId);
+    if (!device) return {};
+
+    std::optional<int32_t> eventHubId = device->getBatteryEventHubId();
+    if (!eventHubId) return {};
+    const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
+    if (batteryIds.empty()) {
+        ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId);
+        return {};
+    }
+    const auto batteryInfo = mEventHub->getRawBatteryInfo(*eventHubId, batteryIds.front());
+    if (!batteryInfo) {
+        ALOGW("%s: Failed to get RawBatteryInfo for battery %d of EventHub device %d", __func__,
+              batteryIds.front(), *eventHubId);
+        return {};
+    }
+    return batteryInfo->path;
+}
+
 std::vector<InputDeviceLightInfo> InputReader::getLights(int32_t deviceId) {
     std::scoped_lock _l(mLock);
 
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 24194a7..fbce87f 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -99,6 +99,8 @@
 
     std::optional<int32_t> getBatteryStatus(int32_t deviceId) override;
 
+    std::optional<std::string> getBatteryDevicePath(int32_t deviceId) override;
+
     std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) override;
 
     std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) override;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index cd853a6..7ee6950 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -4718,36 +4718,6 @@
 
 // We have a focused application, but no focused window
 TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
-    FocusRequest request;
-    request.token = nullptr;
-    request.windowName = "";
-    request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-    request.displayId = mWindow->getInfo()->displayId;
-    mDispatcher->setFocusedWindow(request);
-    mWindow->consumeFocusEvent(false);
-
-    // taps on the window work as normal
-    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
-              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
-                               WINDOW_LOCATION));
-    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
-    mDispatcher->waitForIdle();
-    mFakePolicy->assertNotifyAnrWasNotCalled();
-
-    // Once a focused event arrives, we get an ANR for this application
-    // We specify the injection timeout to be smaller than the application timeout, to ensure that
-    // injection times out (instead of failing).
-    const InputEventInjectionResult result =
-            injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
-                      InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
-    ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
-    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
-    ASSERT_TRUE(mDispatcher->waitForIdle());
-}
-
-// We have a focused application, but we are waiting on the requested window to become focusable
-TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_PendingFocusedRequest) {
     mWindow->setFocusable(false);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
     mWindow->consumeFocusEvent(false);
@@ -4768,7 +4738,7 @@
                       InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
     const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
+    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
     ASSERT_TRUE(mDispatcher->waitForIdle());
 }
 
@@ -4818,10 +4788,11 @@
             injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
                       InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
-    const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
+    const std::chrono::duration appTimeout =
+            mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(appTimeout, mApplication);
 
-    std::this_thread::sleep_for(timeout);
+    std::this_thread::sleep_for(appTimeout);
     // ANR should not be raised again. It is up to policy to do that if it desires.
     mFakePolicy->assertNotifyAnrWasNotCalled();
 
@@ -4842,8 +4813,8 @@
                       InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
     ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
 
-    const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
-    mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
+    const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+    mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
 
     // Future focused events get dropped right away
     ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher));
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 19a7d86..ee6993c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -81,6 +81,7 @@
 static constexpr int32_t DEFAULT_BATTERY = 1;
 static constexpr int32_t BATTERY_STATUS = 4;
 static constexpr int32_t BATTERY_CAPACITY = 66;
+static const std::string BATTERY_DEVPATH = "/sys/devices/mydevice/power_supply/mybattery";
 static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000;
 static constexpr int32_t LIGHT_COLOR = 0x7F448866;
 static constexpr int32_t LIGHT_PLAYER_ID = 2;
@@ -1017,7 +1018,12 @@
 
     std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
                                                     int32_t batteryId) const override {
-        return std::nullopt;
+        if (batteryId != DEFAULT_BATTERY) return {};
+        static const auto BATTERY_INFO = RawBatteryInfo{.id = DEFAULT_BATTERY,
+                                                        .name = "default battery",
+                                                        .flags = InputBatteryClass::CAPACITY,
+                                                        .path = BATTERY_DEVPATH};
+        return BATTERY_INFO;
     }
 
     std::vector<int32_t> getRawLightIds(int32_t deviceId) const override {
@@ -2235,6 +2241,21 @@
     ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS);
 }
 
+TEST_F(InputReaderTest, BatteryGetDevicePath) {
+    constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+    ftl::Flags<InputDeviceClass> deviceClass =
+            InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+    constexpr int32_t eventHubId = 1;
+    const char* DEVICE_LOCATION = "BLUETOOTH";
+    std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+    device->addController<FakePeripheralController>(eventHubId);
+    mReader->pushNextDevice(device);
+
+    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+
+    ASSERT_EQ(mReader->getBatteryDevicePath(deviceId), BATTERY_DEVPATH);
+}
+
 TEST_F(InputReaderTest, LightGetColor) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
     ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index f15d871..f5bd297 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -107,6 +107,10 @@
         return reader->getBatteryStatus(deviceId);
     }
 
+    std::optional<std::string> getBatteryDevicePath(int32_t deviceId) {
+        return reader->getBatteryDevicePath(deviceId);
+    }
+
     std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) {
         return reader->getLights(deviceId);
     }
@@ -232,6 +236,7 @@
                 },
                 [&]() -> void { reader->getBatteryCapacity(fdp->ConsumeIntegral<int32_t>()); },
                 [&]() -> void { reader->getBatteryStatus(fdp->ConsumeIntegral<int32_t>()); },
+                [&]() -> void { reader->getBatteryDevicePath(fdp->ConsumeIntegral<int32_t>()); },
                 [&]() -> void { reader->getLights(fdp->ConsumeIntegral<int32_t>()); },
                 [&]() -> void { reader->getSensors(fdp->ConsumeIntegral<int32_t>()); },
                 [&]() -> void {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 16cb41b..5e84be1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -56,6 +56,9 @@
     // similar requests if needed.
     virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
 
+    // Sends the brightness setting to HWC
+    virtual void applyDisplayBrightness(const bool applyImmediately) = 0;
+
 protected:
     ~Display() = default;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 9753a6c..a738da0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -53,31 +53,8 @@
     // Called before composition starts. Should return true if this layer has
     // pending updates which would require an extra display refresh cycle to
     // process.
-    virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
-
-    // Used with latchCompositionState()
-    enum class StateSubset {
-        // Gets the basic geometry (bounds, transparent region, visibility,
-        // transforms, alpha) for the layer, for computing visibility and
-        // coverage.
-        BasicGeometry,
-
-        // Gets the full geometry (crops, buffer transforms, metadata) and
-        // content (buffer or color) state for the layer.
-        GeometryAndContent,
-
-        // Gets the per frame content (buffer or color) state for the layer.
-        Content,
-
-        // Gets the cursor state for the layer.
-        Cursor,
-    };
-
-    // Prepares the output-independent composition state for the layer. The
-    // StateSubset argument selects what portion of the state is actually needed
-    // by the CompositionEngine code, since computing everything may be
-    // expensive.
-    virtual void prepareCompositionState(StateSubset) = 0;
+    virtual bool onPreComposition(nsecs_t refreshStartTime,
+                                  bool updatingOutputGeometryThisFrame) = 0;
 
     struct ClientCompositionTargetSettings {
         enum class BlurSetting {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 2203639..874b330 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -262,9 +262,6 @@
     // Presents the output, finalizing all composition details
     virtual void present(const CompositionRefreshArgs&) = 0;
 
-    // Latches the front-end layer state for each output layer
-    virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
-
     // Enables predicting composition strategy to run client composition earlier
     virtual void setPredictCompositionStrategy(bool) = 0;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 386808d..0907926 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -51,8 +51,6 @@
     // Debugging
     void dump(std::string&) const override;
 
-    void updateLayerStateFromFE(CompositionRefreshArgs& args);
-
     // Testing
     void setNeedsAnotherUpdateForTest(bool);
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index fa7bc5d..33a10a3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -72,6 +72,7 @@
             const compositionengine::DisplayColorProfileCreationArgs&) override;
     void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
     void createClientCompositionCache(uint32_t cacheSize) override;
+    void applyDisplayBrightness(const bool applyImmediately) override;
 
     // Internal helpers used by chooseCompositionStrategy()
     using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 38a391b..23d5570 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -89,7 +89,6 @@
                                     compositionengine::Output::CoverageState&) override;
     void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override;
 
-    void updateLayerStateFromFE(const CompositionRefreshArgs&) const override;
     void updateCompositionState(const compositionengine::CompositionRefreshArgs&) override;
     void planComposition() override;
     void writeCompositionState(const compositionengine::CompositionRefreshArgs&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 72e6f3b..7e99ec2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
     MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
     MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
     MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+    MOCK_METHOD1(applyDisplayBrightness, void(const bool));
     MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 2b704e6..be0dbce 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -42,9 +42,8 @@
 
     MOCK_CONST_METHOD0(getCompositionState, const LayerFECompositionState*());
 
-    MOCK_METHOD1(onPreComposition, bool(nsecs_t));
+    MOCK_METHOD2(onPreComposition, bool(nsecs_t, bool));
 
-    MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset));
     MOCK_CONST_METHOD1(prepareClientComposition,
                        std::optional<compositionengine::LayerFE::LayerSettings>(
                                compositionengine::LayerFE::ClientCompositionTargetSettings&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 2a04949..7592cac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -91,7 +91,6 @@
                  void(sp<compositionengine::LayerFE>&, compositionengine::Output::CoverageState&));
     MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&));
 
-    MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&));
     MOCK_METHOD1(updateCompositionState, void(const CompositionRefreshArgs&));
     MOCK_METHOD0(planComposition, void());
     MOCK_METHOD1(writeCompositionState, void(const CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 6203dc6..855507e 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -105,8 +105,6 @@
         }
     }
 
-    updateLayerStateFromFE(args);
-
     for (const auto& output : args.outputs) {
         output->present(args);
     }
@@ -119,8 +117,6 @@
     for (const auto& output : args.outputs) {
         for (auto* layer : output->getOutputLayersOrderedByZ()) {
             if (layer->isHardwareCursor()) {
-                // Latch the cursor composition state from each front-end layer.
-                layer->getLayerFE().prepareCompositionState(LayerFE::StateSubset::Cursor);
                 layer->writeCursorPositionToHWC();
             }
         }
@@ -136,7 +132,7 @@
     mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     for (auto& layer : args.layers) {
-        if (layer->onPreComposition(mRefreshStartTime)) {
+        if (layer->onPreComposition(mRefreshStartTime, args.updatingOutputGeometryThisFrame)) {
             needsAnotherUpdate = true;
         }
     }
@@ -152,12 +148,5 @@
     mNeedsAnotherUpdate = value;
 }
 
-void CompositionEngine::updateLayerStateFromFE(CompositionRefreshArgs& args) {
-    // Update the composition state from each front-end layer
-    for (const auto& output : args.outputs) {
-        output->updateLayerStateFromFE(args);
-    }
-}
-
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 0ebbcd0..0b69d44 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -203,6 +203,24 @@
     setReleasedLayers(std::move(releasedLayers));
 }
 
+void Display::applyDisplayBrightness(const bool applyImmediately) {
+    auto& hwc = getCompositionEngine().getHwComposer();
+    const auto halDisplayId = HalDisplayId::tryCast(*getDisplayId());
+    if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+        physicalDisplayId && getState().displayBrightness) {
+        const status_t result =
+                hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+                                         getState().displayBrightnessNits,
+                                         Hwc2::Composer::DisplayBrightnessOptions{
+                                                 .applyImmediately = applyImmediately})
+                        .get();
+        ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+                 getName().c_str(), result, strerror(-result));
+    }
+    // Clear out the display brightness now that it's been communicated to composer.
+    editState().displayBrightness.reset();
+}
+
 void Display::beginFrame() {
     Output::beginFrame();
 
@@ -212,20 +230,7 @@
         return;
     }
 
-    auto& hwc = getCompositionEngine().getHwComposer();
-    if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
-        physicalDisplayId && getState().displayBrightness) {
-        const status_t result =
-                hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
-                                         getState().displayBrightnessNits,
-                                         Hwc2::Composer::DisplayBrightnessOptions{
-                                                 .applyImmediately = false})
-                        .get();
-        ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
-                 getName().c_str(), result, strerror(-result));
-    }
-    // Clear out the display brightness now that it's been communicated to composer.
-    editState().displayBrightness.reset();
+    applyDisplayBrightness(false);
 }
 
 bool Display::chooseCompositionStrategy(
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index b5894cf..e3f3680 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -501,7 +501,6 @@
     // appear on multiple outputs.
     if (!coverage.latchedLayers.count(layerFE)) {
         coverage.latchedLayers.insert(layerFE);
-        layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry);
     }
 
     // Only consider the layers on this output
@@ -725,14 +724,6 @@
     // The base class does nothing with this call.
 }
 
-void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
-    for (auto* layer : getOutputLayersOrderedByZ()) {
-        layer->getLayerFE().prepareCompositionState(
-                args.updatingGeometryThisFrame ? LayerFE::StateSubset::GeometryAndContent
-                                               : LayerFE::StateSubset::Content);
-    }
-}
-
 void Output::updateCompositionState(const compositionengine::CompositionRefreshArgs& refreshArgs) {
     ATRACE_CALL();
     ALOGV(__FUNCTION__);
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index de9de01..b570979 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -108,12 +108,6 @@
     EXPECT_CALL(*mOutput2, prepare(Ref(mRefreshArgs), _));
     EXPECT_CALL(*mOutput3, prepare(Ref(mRefreshArgs), _));
 
-    // The next step in presenting is to make sure all outputs have the latest
-    // state from the front-end (SurfaceFlinger).
-    EXPECT_CALL(*mOutput1, updateLayerStateFromFE(Ref(mRefreshArgs)));
-    EXPECT_CALL(*mOutput2, updateLayerStateFromFE(Ref(mRefreshArgs)));
-    EXPECT_CALL(*mOutput3, updateLayerStateFromFE(Ref(mRefreshArgs)));
-
     // The last step is to actually present each output.
     EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs)));
     EXPECT_CALL(*mOutput2, present(Ref(mRefreshArgs)));
@@ -175,21 +169,18 @@
     {
         InSequence seq;
         EXPECT_CALL(mOutput2Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
-        EXPECT_CALL(*mOutput2Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
         EXPECT_CALL(mOutput2Layer1.outputLayer, writeCursorPositionToHWC());
     }
 
     {
         InSequence seq;
         EXPECT_CALL(mOutput3Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
-        EXPECT_CALL(*mOutput3Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
         EXPECT_CALL(mOutput3Layer1.outputLayer, writeCursorPositionToHWC());
     }
 
     {
         InSequence seq;
         EXPECT_CALL(mOutput3Layer2.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
-        EXPECT_CALL(*mOutput3Layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
         EXPECT_CALL(mOutput3Layer2.outputLayer, writeCursorPositionToHWC());
     }
 
@@ -222,9 +213,12 @@
     nsecs_t ts1 = 0;
     nsecs_t ts2 = 0;
     nsecs_t ts3 = 0;
-    EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
-    EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
-    EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
+    EXPECT_CALL(*mLayer1FE, onPreComposition(_, _))
+            .WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
+    EXPECT_CALL(*mLayer2FE, onPreComposition(_, _))
+            .WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
+    EXPECT_CALL(*mLayer3FE, onPreComposition(_, _))
+            .WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
 
     mRefreshArgs.outputs = {mOutput1};
     mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
@@ -238,9 +232,9 @@
 }
 
 TEST_F(CompositionTestPreComposition, preCompositionDefaultsToNoUpdateNeeded) {
-    EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false));
-    EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
-    EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)).WillOnce(Return(false));
 
     mEngine.setNeedsAnotherUpdateForTest(true);
 
@@ -255,9 +249,9 @@
 
 TEST_F(CompositionTestPreComposition,
        preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) {
-    EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true));
-    EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
-    EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)).WillOnce(Return(true));
+    EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)).WillOnce(Return(false));
+    EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)).WillOnce(Return(false));
 
     mRefreshArgs.outputs = {mOutput1};
     mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index ace2864..eb209e9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -758,56 +758,6 @@
 }
 
 /*
- * Output::updateLayerStateFromFE()
- */
-
-using OutputUpdateLayerStateFromFETest = OutputTest;
-
-TEST_F(OutputUpdateLayerStateFromFETest, handlesNoOutputLayerCase) {
-    CompositionRefreshArgs refreshArgs;
-
-    mOutput->updateLayerStateFromFE(refreshArgs);
-}
-
-TEST_F(OutputUpdateLayerStateFromFETest, preparesContentStateForAllContainedLayers) {
-    InjectedLayer layer1;
-    InjectedLayer layer2;
-    InjectedLayer layer3;
-
-    EXPECT_CALL(*layer1.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
-    EXPECT_CALL(*layer2.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
-    EXPECT_CALL(*layer3.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
-
-    injectOutputLayer(layer1);
-    injectOutputLayer(layer2);
-    injectOutputLayer(layer3);
-
-    CompositionRefreshArgs refreshArgs;
-    refreshArgs.updatingGeometryThisFrame = false;
-
-    mOutput->updateLayerStateFromFE(refreshArgs);
-}
-
-TEST_F(OutputUpdateLayerStateFromFETest, preparesGeometryAndContentStateForAllContainedLayers) {
-    InjectedLayer layer1;
-    InjectedLayer layer2;
-    InjectedLayer layer3;
-
-    EXPECT_CALL(*layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
-    EXPECT_CALL(*layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
-    EXPECT_CALL(*layer3.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
-
-    injectOutputLayer(layer1);
-    injectOutputLayer(layer2);
-    injectOutputLayer(layer3);
-
-    CompositionRefreshArgs refreshArgs;
-    refreshArgs.updatingGeometryThisFrame = true;
-
-    mOutput->updateLayerStateFromFE(refreshArgs);
-}
-
-/*
  * Output::updateAndWriteCompositionState()
  */
 
@@ -1536,9 +1486,6 @@
 
 TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
     EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
-    EXPECT_CALL(*mLayer.layerFE,
-                prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry));
-
     mGeomSnapshots.clear();
 
     ensureOutputLayerIfVisible();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index ebaf35a..029e449 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -164,6 +164,15 @@
 }
 
 void DisplayDevice::setPowerMode(hal::PowerMode mode) {
+    if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
+        if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+            getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+            mBrightness = *mStagedBrightness;
+        }
+        mStagedBrightness = std::nullopt;
+        getCompositionDisplay()->applyDisplayBrightness(true);
+    }
+
     mPowerMode = mode;
 
     getCompositionDisplay()->setCompositionEnabled(mPowerMode.has_value() &&
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1c720cc..91e32f3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -465,6 +465,10 @@
     for (const sp<Layer>& child : mDrawingChildren) {
         child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
     }
+
+    if (mPotentialCursor) {
+        prepareCursorCompositionState();
+    }
 }
 
 Rect Layer::getCroppedBufferSize(const State& s) const {
@@ -650,30 +654,6 @@
     return sp<compositionengine::LayerFE>::fromExisting(layerFE);
 }
 
-void Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) {
-    using StateSubset = compositionengine::LayerFE::StateSubset;
-
-    switch (subset) {
-        case StateSubset::BasicGeometry:
-            prepareBasicGeometryCompositionState();
-            break;
-
-        case StateSubset::GeometryAndContent:
-            prepareBasicGeometryCompositionState();
-            prepareGeometryCompositionState();
-            preparePerFrameCompositionState();
-            break;
-
-        case StateSubset::Content:
-            preparePerFrameCompositionState();
-            break;
-
-        case StateSubset::Cursor:
-            prepareCursorCompositionState();
-            break;
-    }
-}
-
 const char* Layer::getDebugName() const {
     return mName.c_str();
 }
@@ -3197,8 +3177,7 @@
                       const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
                       bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
                       const FrameTimelineInfo& info) {
-    ATRACE_CALL();
-
+    ATRACE_FORMAT("setBuffer %s - hasBuffer=%s", getDebugName(), (buffer ? "true" : "false"));
     if (!buffer) {
         return false;
     }
@@ -3207,6 +3186,7 @@
             bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged);
     const uint64_t frameNumber =
             frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1;
+    ATRACE_FORMAT_INSTANT("setBuffer %s - %" PRIu64, getDebugName(), frameNumber);
 
     if (mDrawingState.buffer) {
         mReleasePreviousBuffer = true;
@@ -3426,7 +3406,7 @@
     return fenceSignaled;
 }
 
-bool Layer::onPreComposition(nsecs_t refreshStartTime) {
+bool Layer::onPreComposition(nsecs_t refreshStartTime, bool /* updatingOutputGeometryThisFrame */) {
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->refreshStartTime = refreshStartTime;
     }
@@ -4240,6 +4220,18 @@
     return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
 }
 
+void Layer::updateSnapshot(bool updateGeometry) {
+    if (!getCompositionEngineLayerFE()) {
+        return;
+    }
+
+    if (updateGeometry) {
+        prepareBasicGeometryCompositionState();
+        prepareGeometryCompositionState();
+    }
+    preparePerFrameCompositionState();
+}
+
 // ---------------------------------------------------------------------------
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f6b9b0f..5030fd8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -574,9 +574,8 @@
     // implements compositionengine::LayerFE
     const compositionengine::LayerFECompositionState* getCompositionState() const;
     bool fenceHasSignaled() const;
-    bool onPreComposition(nsecs_t);
-    void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
-
+    // Called before composition. updatingOutputGeometryThisFrame is used by ARC++'s Layer subclass.
+    bool onPreComposition(nsecs_t refreshStartTime, bool updatingOutputGeometryThisFrame);
     std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
             compositionengine::LayerFE::ClientCompositionTargetSettings&) const override;
     void onLayerDisplayed(ftl::SharedFuture<FenceResult>);
@@ -868,6 +867,7 @@
     bool simpleBufferUpdate(const layer_state_t&) const;
 
     static bool isOpaqueFormat(PixelFormat format);
+    void updateSnapshot(bool updateGeometry);
 
 protected:
     friend class impl::SurfaceInterceptor;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index d270655..00886f0 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -280,6 +280,15 @@
     ATRACE_CALL();
     ALOGV("%s: %zu layers", __func__, layers.size());
 
+    const auto& activeMode = *getActiveModeItLocked()->second;
+
+    // Keep the display at max refresh rate for the duration of powering on the display.
+    if (signals.powerOnImminent) {
+        ALOGV("Power On Imminent");
+        const auto& max = getMaxRefreshRateByPolicyLocked(activeMode.getGroup());
+        return {max, GlobalSignals{.powerOnImminent = true}};
+    }
+
     int noVoteLayers = 0;
     int minVoteLayers = 0;
     int maxVoteLayers = 0;
@@ -326,7 +335,6 @@
 
     const Policy* policy = getCurrentPolicyLocked();
     const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
-    const auto& activeMode = *getActiveModeItLocked()->second;
 
     // If the default mode group is different from the group of current mode,
     // this means a layer requesting a seamed mode switch just disappeared and
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index b2cfb03..19bcb94 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -185,9 +185,13 @@
         bool touch = false;
         // True if the system hasn't seen any buffers posted to layers recently.
         bool idle = false;
+        // Whether the display is about to be powered on, or has been in PowerMode::ON
+        // within the timeout of DisplayPowerTimer.
+        bool powerOnImminent = false;
 
         bool operator==(GlobalSignals other) const {
-            return touch == other.touch && idle == other.idle;
+            return touch == other.touch && idle == other.idle &&
+                    powerOnImminent == other.powerOnImminent;
         }
     };
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index bec39a7..ff6b461 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -704,17 +704,13 @@
 
     const auto configs = holdRefreshRateConfigs();
 
-    // If Display Power is not in normal operation we want to be in performance mode. When coming
-    // back to normal mode, a grace period is given with DisplayPowerTimer.
-    if (mDisplayPowerTimer &&
-        (mPolicy.displayPowerMode != hal::PowerMode::ON ||
-         mPolicy.displayPowerTimer == TimerState::Reset)) {
-        constexpr GlobalSignals kNoSignals;
-        return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
-    }
+    const bool powerOnImminent = mDisplayPowerTimer &&
+            (mPolicy.displayPowerMode != hal::PowerMode::ON ||
+             mPolicy.displayPowerTimer == TimerState::Reset);
 
     const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
-                                .idle = mPolicy.idleTimer == TimerState::Expired};
+                                .idle = mPolicy.idleTimer == TimerState::Expired,
+                                .powerOnImminent = powerOnImminent};
 
     return configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9dd3713..e31490c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2189,10 +2189,6 @@
         displayIds.push_back(display->getId());
     }
     mPowerAdvisor->setDisplays(displayIds);
-    mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
-        if (auto layerFE = layer->getCompositionEngineLayerFE())
-            refreshArgs.layers.push_back(layerFE);
-    });
 
     if (DOES_CONTAIN_BORDER) {
         refreshArgs.borderInfoList.clear();
@@ -2223,6 +2219,12 @@
 
     refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
     refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
+    mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
+        layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame);
+        if (auto layerFE = layer->getCompositionEngineLayerFE()) {
+            refreshArgs.layers.push_back(layerFE);
+        }
+    });
     refreshArgs.blursAreExpensive = mBlursAreExpensive;
     refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
 
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 7a5f229..a06c41b 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -78,9 +78,8 @@
 Layer supports the following parameters:
 1. Display Connection Types (parameter name: `fakeDisplay`)
 2. State Sets (parameter name: `traverseInZOrder`)
-3. State Subsets (parameter name: `prepareCompositionState`)
-4. Disconnect modes (parameter name: `disconnect`)
-5. Data Spaces (parameter name: `setDataspace`)
+3. Disconnect modes (parameter name: `disconnect`)
+4. Data Spaces (parameter name: `setDataspace`)
 
 You can find the possible values in the fuzzer's source code.
 
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 5b2ec96..9ece260 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -148,7 +148,8 @@
     layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
 
     layer->fenceHasSignaled();
-    layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
+    layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>(),
+                            false /*updatingOutputGeometryThisFrame*/);
     const std::vector<sp<CallbackHandle>> callbacks;
     layer->setTransactionCompletedListeners(callbacks);
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 4f20932..5d9b2a8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -977,6 +977,32 @@
     EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
 }
 
+TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) {
+    RefreshRateConfigs configs(kModes_60_90, kModeId60);
+
+    auto [refreshRate, signals] = configs.getBestRefreshRate({}, {});
+    EXPECT_FALSE(signals.powerOnImminent);
+    EXPECT_EQ(kMode90, refreshRate);
+
+    std::tie(refreshRate, signals) = configs.getBestRefreshRate({}, {.powerOnImminent = true});
+    EXPECT_TRUE(signals.powerOnImminent);
+    EXPECT_EQ(kMode90, refreshRate);
+
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+    auto& lr1 = layers[0];
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60_Hz;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+
+    std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = false});
+    EXPECT_FALSE(signals.powerOnImminent);
+    EXPECT_EQ(kMode60, refreshRate);
+
+    std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = true});
+    EXPECT_TRUE(signals.powerOnImminent);
+    EXPECT_EQ(kMode90, refreshRate);
+}
+
 TEST_F(RefreshRateConfigsTest, touchConsidered) {
     RefreshRateConfigs configs(kModes_60_90, kModeId60);