Merge "GestureConverter: initialize mThreeFingerTapShortcutEnabled" into main
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index c6fd487..4b9dcf8 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -498,9 +498,9 @@
                 // same thread, everything should have happened in a nested call. Otherwise,
                 // the callback will be processed on another thread.
                 if (callIsOneway || callbackIsOneway || delayed) {
-                    using std::literals::chrono_literals::operator""s;
+                    using std::literals::chrono_literals::operator""ms;
                     RpcMutexUniqueLock _l(cb->mMutex);
-                    cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+                    cb->mCv.wait_for(_l, 1500ms, [&] { return !cb->mValues.empty(); });
                 }
 
                 EXPECT_EQ(cb->mValues.size(), 1UL)
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
index 6bf79d4..a8acded 100644
--- a/libs/debugstore/rust/src/core.rs
+++ b/libs/debugstore/rust/src/core.rs
@@ -48,7 +48,7 @@
     ///
     /// This constant is used as a part of the debug store's data format,
     /// allowing for version tracking and compatibility checks.
-    const ENCODE_VERSION: u32 = 1;
+    const ENCODE_VERSION: u32 = 2;
 
     /// Creates a new instance of `DebugStore` with specified event limit and maximum delay.
     fn new() -> Self {
@@ -129,7 +129,7 @@
         write!(
             f,
             "{}",
-            self.event_store.fold(String::new(), |mut acc, event| {
+            self.event_store.rfold(String::new(), |mut acc, event| {
                 if !acc.is_empty() {
                     acc.push_str("||");
                 }
diff --git a/libs/debugstore/rust/src/storage.rs b/libs/debugstore/rust/src/storage.rs
index 2ad7f4e..47760f3 100644
--- a/libs/debugstore/rust/src/storage.rs
+++ b/libs/debugstore/rust/src/storage.rs
@@ -32,14 +32,18 @@
         self.insertion_buffer.force_push(value);
     }
 
-    /// Folds over the elements in the storage using the provided function.
-    pub fn fold<U, F>(&self, init: U, mut func: F) -> U
+    /// Folds over the elements in the storage in reverse order using the provided function.
+    pub fn rfold<U, F>(&self, init: U, mut func: F) -> U
     where
         F: FnMut(U, &T) -> U,
     {
-        let mut acc = init;
+        let mut items = Vec::new();
         while let Some(value) = self.insertion_buffer.pop() {
-            acc = func(acc, &value);
+            items.push(value);
+        }
+        let mut acc = init;
+        for value in items.iter().rev() {
+            acc = func(acc, value);
         }
         acc
     }
@@ -59,18 +63,18 @@
         let storage = Storage::<i32, 10>::new();
         storage.insert(7);
 
-        let sum = storage.fold(0, |acc, &x| acc + x);
+        let sum = storage.rfold(0, |acc, &x| acc + x);
         assert_eq!(sum, 7, "The sum of the elements should be equal to the inserted value.");
     }
 
     #[test]
-    fn test_fold_functionality() {
+    fn test_rfold_functionality() {
         let storage = Storage::<i32, 5>::new();
         storage.insert(1);
         storage.insert(2);
         storage.insert(3);
 
-        let sum = storage.fold(0, |acc, &x| acc + x);
+        let sum = storage.rfold(0, |acc, &x| acc + x);
         assert_eq!(
             sum, 6,
             "The sum of the elements should be equal to the sum of inserted values."
@@ -84,13 +88,13 @@
         storage.insert(2);
         storage.insert(5);
 
-        let first_sum = storage.fold(0, |acc, &x| acc + x);
+        let first_sum = storage.rfold(0, |acc, &x| acc + x);
         assert_eq!(first_sum, 8, "The sum of the elements should be equal to the inserted values.");
 
         storage.insert(30);
         storage.insert(22);
 
-        let second_sum = storage.fold(0, |acc, &x| acc + x);
+        let second_sum = storage.rfold(0, |acc, &x| acc + x);
         assert_eq!(
             second_sum, 52,
             "The sum of the elements should be equal to the inserted values."
@@ -103,7 +107,7 @@
         storage.insert(1);
         // This value should overwrite the previously inserted value (1).
         storage.insert(4);
-        let sum = storage.fold(0, |acc, &x| acc + x);
+        let sum = storage.rfold(0, |acc, &x| acc + x);
         assert_eq!(sum, 4, "The sum of the elements should be equal to the inserted values.");
     }
 
@@ -128,7 +132,24 @@
             thread.join().expect("Thread should finish without panicking");
         }
 
-        let count = storage.fold(0, |acc, _| acc + 1);
+        let count = storage.rfold(0, |acc, _| acc + 1);
         assert_eq!(count, 100, "Storage should be filled to its limit with concurrent insertions.");
     }
+
+    #[test]
+    fn test_rfold_order() {
+        let storage = Storage::<i32, 5>::new();
+        storage.insert(1);
+        storage.insert(2);
+        storage.insert(3);
+
+        let mut result = Vec::new();
+        storage.rfold((), |_, &x| result.push(x));
+
+        assert_eq!(
+            result,
+            vec![3, 2, 1],
+            "Elements should be processed in reverse order of insertion"
+        );
+    }
 }
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index af50a29..1fde45b 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -21,9 +21,25 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+aconfig_declarations {
+    name: "graphicsenv_flags",
+    package: "com.android.graphics.graphicsenv.flags",
+    container: "system",
+    srcs: ["graphicsenv_flags.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "graphicsenv_flags_c_lib",
+    aconfig_declarations: "graphicsenv_flags",
+}
+
 cc_library_shared {
     name: "libgraphicsenv",
 
+    defaults: [
+        "aconfig_lib_cc_static_link.defaults",
+    ],
+
     srcs: [
         "GpuStatsInfo.cpp",
         "GraphicsEnv.cpp",
@@ -35,6 +51,10 @@
         "-Werror",
     ],
 
+    static_libs: [
+        "graphicsenv_flags_c_lib",
+    ],
+
     shared_libs: [
         "libbase",
         "libbinder",
@@ -42,6 +62,7 @@
         "libdl_android",
         "liblog",
         "libutils",
+        "server_configurable_flags",
     ],
 
     header_libs: [
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 4874dbd..4bc2611 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -29,6 +29,7 @@
 #include <android-base/strings.h>
 #include <android/dlext.h>
 #include <binder/IServiceManager.h>
+#include <com_android_graphics_graphicsenv_flags.h>
 #include <graphicsenv/IGpuService.h>
 #include <log/log.h>
 #include <nativeloader/dlext_namespaces.h>
@@ -70,6 +71,8 @@
 }
 } // namespace
 
+namespace graphicsenv_flags = com::android::graphics::graphicsenv::flags;
+
 namespace android {
 
 enum NativeLibrary {
@@ -624,10 +627,36 @@
     return mPackageName;
 }
 
+// List of ANGLE features to enable, specified in the Global.Settings value "angle_egl_features".
 const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() {
     return mAngleEglFeatures;
 }
 
+void GraphicsEnv::getAngleFeatureOverrides(std::vector<const char*>& enabled,
+                                           std::vector<const char*>& disabled) {
+    if (!graphicsenv_flags::feature_overrides()) {
+        return;
+    }
+
+    for (const FeatureConfig& feature : mFeatureOverrides.mGlobalFeatures) {
+        if (feature.mEnabled) {
+            enabled.push_back(feature.mFeatureName.c_str());
+        } else {
+            disabled.push_back(feature.mFeatureName.c_str());
+        }
+    }
+
+    if (mFeatureOverrides.mPackageFeatures.count(mPackageName)) {
+        for (const FeatureConfig& feature : mFeatureOverrides.mPackageFeatures[mPackageName]) {
+            if (feature.mEnabled) {
+                enabled.push_back(feature.mFeatureName.c_str());
+            } else {
+                disabled.push_back(feature.mFeatureName.c_str());
+            }
+        }
+    }
+}
+
 android_namespace_t* GraphicsEnv::getAngleNamespace() {
     std::lock_guard<std::mutex> lock(mNamespaceMutex);
 
diff --git a/libs/graphicsenv/graphicsenv_flags.aconfig b/libs/graphicsenv/graphicsenv_flags.aconfig
new file mode 100644
index 0000000..ac66362
--- /dev/null
+++ b/libs/graphicsenv/graphicsenv_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.graphics.graphicsenv.flags"
+container: "system"
+
+flag {
+  name: "feature_overrides"
+  namespace: "core_graphics"
+  description: "This flag controls the Feature Overrides in GraphicsEnv."
+  bug: "372694741"
+}
diff --git a/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h b/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h
new file mode 100644
index 0000000..2ef54ad
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace android {
+
+class FeatureConfig {
+public:
+    FeatureConfig() = default;
+    FeatureConfig(const FeatureConfig&) = default;
+    virtual ~FeatureConfig() = default;
+
+    std::string mFeatureName;
+    bool mEnabled;
+};
+
+/*
+ * Class for transporting OpenGL ES Feature configurations from GpuService to authorized
+ * recipients.
+ */
+class FeatureOverrides {
+public:
+    FeatureOverrides() = default;
+    FeatureOverrides(const FeatureOverrides&) = default;
+    virtual ~FeatureOverrides() = default;
+
+    std::vector<FeatureConfig> mGlobalFeatures;
+    /* Key: Package Name, Value: Package's Feature Configs */
+    std::map<std::string, std::vector<FeatureConfig>> mPackageFeatures;
+};
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 452e48b..55fa13a 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_UI_GRAPHICS_ENV_H
 #define ANDROID_UI_GRAPHICS_ENV_H 1
 
+#include <graphicsenv/FeatureOverrides.h>
 #include <graphicsenv/GpuStatsInfo.h>
 
 #include <mutex>
@@ -120,6 +121,8 @@
     // Get the app package name.
     std::string& getPackageName();
     const std::vector<std::string>& getAngleEglFeatures();
+    void getAngleFeatureOverrides(std::vector<const char*>& enabled,
+                                  std::vector<const char*>& disabled);
     // Set the persist.graphics.egl system property value.
     void nativeToggleAngleAsSystemDriver(bool enabled);
     bool shouldUseSystemAngle();
@@ -177,6 +180,7 @@
     std::string mPackageName;
     // ANGLE EGL features;
     std::vector<std::string> mAngleEglFeatures;
+    FeatureOverrides mFeatureOverrides;
     // Whether ANGLE should be used.
     bool mShouldUseAngle = false;
     // Whether loader should load system ANGLE.
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 38465b0..24d858c 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -244,12 +244,6 @@
     BQA_LOGV("BLASTBufferQueue created");
 }
 
-BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
-                                   int width, int height, int32_t format)
-      : BLASTBufferQueue(name) {
-    update(surface, width, height, format);
-}
-
 BLASTBufferQueue::~BLASTBufferQueue() {
     TransactionCompletedListener::getInstance()->removeQueueStallListener(this);
     if (mPendingTransactions.empty()) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2beeae0..c6ba7d8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -829,9 +829,7 @@
 
 SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
       : mId(other.mId),
-        mAnimation(other.mAnimation),
-        mEarlyWakeupStart(other.mEarlyWakeupStart),
-        mEarlyWakeupEnd(other.mEarlyWakeupEnd),
+        mFlags(other.mFlags),
         mMayContainBuffer(other.mMayContainBuffer),
         mDesiredPresentTime(other.mDesiredPresentTime),
         mIsAutoTimestamp(other.mIsAutoTimestamp),
@@ -868,9 +866,7 @@
 
 status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
     const uint64_t transactionId = parcel->readUint64();
-    const bool animation = parcel->readBool();
-    const bool earlyWakeupStart = parcel->readBool();
-    const bool earlyWakeupEnd = parcel->readBool();
+    const uint32_t flags = parcel->readUint32();
     const int64_t desiredPresentTime = parcel->readInt64();
     const bool isAutoTimestamp = parcel->readBool();
     const bool logCallPoints = parcel->readBool();
@@ -965,9 +961,7 @@
 
     // Parsing was successful. Update the object.
     mId = transactionId;
-    mAnimation = animation;
-    mEarlyWakeupStart = earlyWakeupStart;
-    mEarlyWakeupEnd = earlyWakeupEnd;
+    mFlags = flags;
     mDesiredPresentTime = desiredPresentTime;
     mIsAutoTimestamp = isAutoTimestamp;
     mFrameTimelineInfo = frameTimelineInfo;
@@ -996,9 +990,7 @@
     const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
 
     parcel->writeUint64(mId);
-    parcel->writeBool(mAnimation);
-    parcel->writeBool(mEarlyWakeupStart);
-    parcel->writeBool(mEarlyWakeupEnd);
+    parcel->writeUint32(mFlags);
     parcel->writeInt64(mDesiredPresentTime);
     parcel->writeBool(mIsAutoTimestamp);
     parcel->writeBool(mLogCallPoints);
@@ -1131,8 +1123,7 @@
     mInputWindowCommands.merge(other.mInputWindowCommands);
 
     mMayContainBuffer |= other.mMayContainBuffer;
-    mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart;
-    mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd;
+    mFlags |= other.mFlags;
     mApplyToken = other.mApplyToken;
 
     mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo);
@@ -1154,15 +1145,13 @@
     mInputWindowCommands.clear();
     mUncacheBuffers.clear();
     mMayContainBuffer = false;
-    mAnimation = false;
-    mEarlyWakeupStart = false;
-    mEarlyWakeupEnd = false;
     mDesiredPresentTime = 0;
     mIsAutoTimestamp = true;
     mFrameTimelineInfo = {};
     mApplyToken = nullptr;
     mMergedTransactionIds.clear();
     mLogCallPoints = false;
+    mFlags = 0;
 }
 
 uint64_t SurfaceComposerClient::Transaction::getId() {
@@ -1325,7 +1314,6 @@
 
     Vector<ComposerState> composerStates;
     Vector<DisplayState> displayStates;
-    uint32_t flags = 0;
 
     for (auto const& kv : mComposerStates) {
         composerStates.add(kv.second);
@@ -1333,32 +1321,26 @@
 
     displayStates = std::move(mDisplayStates);
 
-    if (mAnimation) {
-        flags |= ISurfaceComposer::eAnimation;
-    }
     if (oneWay) {
         if (synchronous) {
             ALOGE("Transaction attempted to set synchronous and one way at the same time"
                   " this is an invalid request. Synchronous will win for safety");
         } else {
-            flags |= ISurfaceComposer::eOneWay;
+            mFlags |= ISurfaceComposer::eOneWay;
         }
     }
 
-    // If both mEarlyWakeupStart and mEarlyWakeupEnd are set
+    // If both ISurfaceComposer::eEarlyWakeupStart and ISurfaceComposer::eEarlyWakeupEnd are set
     // it is equivalent for none
-    if (mEarlyWakeupStart && !mEarlyWakeupEnd) {
-        flags |= ISurfaceComposer::eEarlyWakeupStart;
+    uint32_t wakeupFlags = ISurfaceComposer::eEarlyWakeupStart | ISurfaceComposer::eEarlyWakeupEnd;
+    if ((mFlags & wakeupFlags) == wakeupFlags) {
+        mFlags &= ~(wakeupFlags);
     }
-    if (mEarlyWakeupEnd && !mEarlyWakeupStart) {
-        flags |= ISurfaceComposer::eEarlyWakeupEnd;
-    }
-
     sp<IBinder> applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken();
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     status_t binderStatus =
-            sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags,
+            sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, mFlags,
                                     applyToken, mInputWindowCommands, mDesiredPresentTime,
                                     mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks,
                                     listenerCallbacks, mId, mMergedTransactionIds);
@@ -1461,15 +1443,15 @@
 }
 
 void SurfaceComposerClient::Transaction::setAnimationTransaction() {
-    mAnimation = true;
+    mFlags |= ISurfaceComposer::eAnimation;
 }
 
 void SurfaceComposerClient::Transaction::setEarlyWakeupStart() {
-    mEarlyWakeupStart = true;
+    mFlags |= ISurfaceComposer::eEarlyWakeupStart;
 }
 
 void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() {
-    mEarlyWakeupEnd = true;
+    mFlags |= ISurfaceComposer::eEarlyWakeupEnd;
 }
 
 layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index f126c0b..b735418 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -141,7 +141,8 @@
                                  ISurfaceComposerClient::eOpaque);
     mBbqChild = mClient->createSurface(String8::format("[BBQ] %s", mName.c_str()), 0, 0, mFormat,
                                        flags, mHandle, {}, &ignore);
-    mBbq = sp<BLASTBufferQueue>::make("[BBQ]" + mName, mBbqChild, mWidth, mHeight, mFormat);
+    mBbq = sp<BLASTBufferQueue>::make("[BBQ] " + mName, /* updateDestinationFrame */ true);
+    mBbq->update(mBbqChild, mWidth, mHeight, mFormat);
 
     // This surface is always consumed by SurfaceFlinger, so the
     // producerControlledByApp value doesn't matter; using false.
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1bc1dd0..7c6f80b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -90,8 +90,6 @@
 class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener {
 public:
     BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
-    BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
-                     int height, int32_t format);
 
     sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
         return mProducer;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d20b346..2215632 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -467,10 +467,7 @@
         std::vector<uint64_t> mMergedTransactionIds;
 
         uint64_t mId;
-
-        bool mAnimation = false;
-        bool mEarlyWakeupStart = false;
-        bool mEarlyWakeupEnd = false;
+        uint32_t mFlags = 0;
 
         // 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
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 53f4a36..e6ee89f 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -81,7 +81,9 @@
 public:
     TestBLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
                          int height, int32_t format)
-          : BLASTBufferQueue(name, surface, width, height, format) {}
+          : BLASTBufferQueue(name) {
+        update(surface, width, height, format);
+    }
 
     void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
                              const std::vector<SurfaceControlStats>& stats) override {
diff --git a/libs/input/tests/InputVerifier_test.cpp b/libs/input/tests/InputVerifier_test.cpp
index e2eb080..5bb1d56 100644
--- a/libs/input/tests/InputVerifier_test.cpp
+++ b/libs/input/tests/InputVerifier_test.cpp
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
+#include <android/input.h>
+#include <android-base/result.h>
 #include <gtest/gtest.h>
+#include <input/Input.h>
 #include <input/InputVerifier.h>
 #include <string>
+#include <vector>
 
 namespace android {
 
@@ -48,7 +52,7 @@
                                      AMOTION_EVENT_ACTION_DOWN,
                                      /*pointerCount=*/properties.size(), properties.data(),
                                      coords.data(), /*flags=*/0);
-    ASSERT_TRUE(result.ok());
+    ASSERT_RESULT_OK(result);
 }
 
 } // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fcd784d..4c4182d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2412,7 +2412,7 @@
         tempTouchState = *oldState;
     }
 
-    bool isSplit = shouldSplitTouch(entry.source);
+    const bool isSplit = shouldSplitTouch(entry.source);
 
     const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||
                                 maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
@@ -2425,11 +2425,6 @@
     const bool newGesture = isDown || maskedAction == AMOTION_EVENT_ACTION_SCROLL ||
             maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
             maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE;
-    const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
-
-    if (newGesture) {
-        isSplit = false;
-    }
 
     if (isDown && tempTouchState.hasHoveringPointers(entry.deviceId)) {
         // Compatibility behaviour: ACTION_DOWN causes HOVER_EXIT to get generated.
@@ -2472,8 +2467,6 @@
             return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
         }
 
-        isSplit = !isFromMouse;
-
         std::vector<sp<WindowInfoHandle>> newTouchedWindows =
                 mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId,
                                                      mTouchStatesByDisplay);
@@ -2647,7 +2640,6 @@
                                              targets);
 
                 // Make a slippery entrance into the new window.
-                isSplit = !isFromMouse;
 
                 ftl::Flags<InputTarget::Flags> targetFlags;
                 if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 8529c72..5cef051 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -26,12 +26,15 @@
 #include <android/binder_manager.h>
 #include <common/FlagManager.h>
 #include <common/trace.h>
+#include <fmt/core.h>
 #include <log/log.h>
 
 #include <aidl/android/hardware/graphics/composer3/BnComposerCallback.h>
 
 #include <algorithm>
 #include <cinttypes>
+#include <string>
+#include <string_view>
 
 #include "HWC2.h"
 
@@ -229,25 +232,32 @@
     HWC2::ComposerCallback& mCallback;
 };
 
-std::string AidlComposer::instance(const std::string& serviceName) {
-    return std::string(AidlIComposer::descriptor) + "/" + serviceName;
+std::string AidlComposer::ensureFullyQualifiedName(std::string_view serviceName) {
+    if (!serviceName.starts_with(AidlIComposer::descriptor)) {
+        return fmt::format("{}/{}", AidlIComposer::descriptor, serviceName);
+    } else {
+        return std::string{serviceName};
+    }
 }
 
-bool AidlComposer::isDeclared(const std::string& serviceName) {
-    return AServiceManager_isDeclared(instance(serviceName).c_str());
+bool AidlComposer::namesAnAidlComposerService(std::string_view serviceName) {
+    if (!serviceName.starts_with(AidlIComposer::descriptor)) {
+        return AServiceManager_isDeclared(ensureFullyQualifiedName(serviceName).c_str());
+    }
+    return true;
 }
 
 AidlComposer::AidlComposer(const std::string& serviceName) {
     // This only waits if the service is actually declared
-    mAidlComposer = AidlIComposer::fromBinder(
-            ndk::SpAIBinder(AServiceManager_waitForService(instance(serviceName).c_str())));
+    mAidlComposer = AidlIComposer::fromBinder(ndk::SpAIBinder(
+            AServiceManager_waitForService(ensureFullyQualifiedName(serviceName).c_str())));
     if (!mAidlComposer) {
         LOG_ALWAYS_FATAL("Failed to get AIDL composer service");
         return;
     }
 
     if (!mAidlComposer->createClient(&mAidlComposerClient).isOk()) {
-        LOG_ALWAYS_FATAL("Can't create AidlComposerClient, fallback to HIDL");
+        LOG_ALWAYS_FATAL("Can't create AidlComposerClient");
         return;
     }
 
@@ -686,6 +696,36 @@
     return error;
 }
 
+Error AidlComposer::getLayerPresentFences(Display display, std::vector<Layer>* outLayers,
+                                          std::vector<int>* outFences,
+                                          std::vector<int64_t>* outLatenciesNanos) {
+    Error error = Error::NONE;
+    std::vector<PresentFence::LayerPresentFence> fences;
+    {
+        mMutex.lock_shared();
+        if (auto reader = getReader(display)) {
+            fences = reader->get().takeLayerPresentFences(translate<int64_t>(display));
+        } else {
+            error = Error::BAD_DISPLAY;
+        }
+        mMutex.unlock_shared();
+    }
+
+    outLayers->reserve(fences.size());
+    outFences->reserve(fences.size());
+    outLatenciesNanos->reserve(fences.size());
+
+    for (auto& fence : fences) {
+        outLayers->emplace_back(translate<Layer>(fence.layer));
+        // take ownership
+        const int fenceOwner = fence.bufferFence.get();
+        *fence.bufferFence.getR() = -1;
+        outFences->emplace_back(fenceOwner);
+        outLatenciesNanos->emplace_back(fence.bufferLatencyNanos);
+    }
+    return error;
+}
+
 Error AidlComposer::presentDisplay(Display display, int* outPresentFence) {
     const auto displayId = translate<int64_t>(display);
     SFTRACE_FORMAT("HwcPresentDisplay %" PRId64, displayId);
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 82006f4..5fcc8b0 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -24,7 +24,7 @@
 #include <functional>
 #include <optional>
 #include <string>
-#include <utility>
+#include <string_view>
 #include <vector>
 
 #include <android/hardware/graphics/composer/2.4/IComposer.h>
@@ -53,7 +53,8 @@
 // Composer is a wrapper to IComposer, a proxy to server-side composer.
 class AidlComposer final : public Hwc2::Composer {
 public:
-    static bool isDeclared(const std::string& serviceName);
+    // Returns true if serviceName appears to be something that is meant to be used by AidlComposer.
+    static bool namesAnAidlComposerService(std::string_view serviceName);
 
     explicit AidlComposer(const std::string& serviceName);
     ~AidlComposer() override;
@@ -106,6 +107,10 @@
     Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
                            std::vector<int>* outReleaseFences) override;
 
+    Error getLayerPresentFences(Display display, std::vector<Layer>* outLayers,
+                                std::vector<int>* outFences,
+                                std::vector<int64_t>* outLatenciesNanos) override;
+
     Error presentDisplay(Display display, int* outPresentFence) override;
 
     Error setActiveConfig(Display display, Config config) override;
@@ -254,8 +259,8 @@
     // this function to execute the command queue.
     Error execute(Display) REQUIRES_SHARED(mMutex);
 
-    // returns the default instance name for the given service
-    static std::string instance(const std::string& serviceName);
+    // Ensures serviceName is fully qualified.
+    static std::string ensureFullyQualifiedName(std::string_view serviceName);
 
     ftl::Optional<std::reference_wrapper<ComposerClientWriter>> getWriter(Display)
             REQUIRES_SHARED(mMutex);
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index d69a923..1e4132c 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -26,7 +26,7 @@
 Composer::~Composer() = default;
 
 std::unique_ptr<Composer> Composer::create(const std::string& serviceName) {
-    if (AidlComposer::isDeclared(serviceName)) {
+    if (AidlComposer::namesAnAidlComposerService(serviceName)) {
         return std::make_unique<AidlComposer>(serviceName);
     }
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 6e431bb..018ee6e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -157,6 +157,10 @@
     virtual Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
                                    std::vector<int>* outReleaseFences) = 0;
 
+    virtual Error getLayerPresentFences(Display display, std::vector<Layer>* outLayers,
+                                        std::vector<int>* outFences,
+                                        std::vector<int64_t>* outLatenciesNanos) = 0;
+
     virtual Error presentDisplay(Display display, int* outPresentFence) = 0;
 
     virtual Error setActiveConfig(Display display, Config config) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index e63a14b..252c6b6 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -640,7 +640,15 @@
                 lutFileDescriptorMapper.emplace_or_replace(layer.get(),
                                                            ndk::ScopedFileDescriptor(
                                                                    layerLut.luts.pfd.release()));
+            } else {
+                ALOGE("getRequestedLuts: invalid luts on layer %" PRIu64 " found"
+                      " on display %" PRIu64 ". pfd.get()=%d, offsets.has_value()=%d",
+                      layerIds[i], mId, layerLut.luts.pfd.get(), layerLut.luts.offsets.has_value());
             }
+        } else {
+            ALOGE("getRequestedLuts: invalid layer %" PRIu64 " found"
+                  " on display %" PRIu64,
+                  layerIds[i], mId);
         }
     }
 
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index ec15539..fc317f3 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -590,6 +590,11 @@
     return Error::NONE;
 }
 
+Error HidlComposer::getLayerPresentFences(Display, std::vector<Layer>*, std::vector<int>*,
+                                          std::vector<int64_t>*) {
+    return Error::UNSUPPORTED;
+}
+
 Error HidlComposer::presentDisplay(Display display, int* outPresentFence) {
     SFTRACE_NAME("HwcPresentDisplay");
     mWriter.selectDisplay(display);
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index cacdb8c..86ca4b1 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -214,6 +214,10 @@
     Error getReleaseFences(Display display, std::vector<Layer>* outLayers,
                            std::vector<int>* outReleaseFences) override;
 
+    Error getLayerPresentFences(Display display, std::vector<Layer>* outLayers,
+                                std::vector<int>* outFences,
+                                std::vector<int64_t>* outLatenciesNanos) override;
+
     Error presentDisplay(Display display, int* outPresentFence) override;
 
     Error setActiveConfig(Display display, Config config) override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1f8557c..d6225e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3271,12 +3271,12 @@
 
     const auto schedule = mScheduler->getVsyncSchedule();
     const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime);
-    const Period vsyncPeriod = schedule->period();
+    const Fps renderRate = pacesetterDisplay->refreshRateSelector().getActiveMode().fps;
     const nsecs_t vsyncPhase =
             mScheduler->getVsyncConfiguration().getCurrentConfigs().late.sfOffset;
 
-    const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase,
-                                            presentLatency.ns());
+    const CompositorTiming compositorTiming(vsyncDeadline.ns(), renderRate.getPeriodNsecs(),
+                                            vsyncPhase, presentLatency.ns());
 
     ui::DisplayMap<ui::LayerStack, const DisplayDevice*> layerStackToDisplay;
     {
@@ -7648,7 +7648,7 @@
 
     if (hdrBuffer && gainmapBuffer) {
         ftl::SharedFuture<FenceResult> hdrRenderFuture =
-                renderScreenImpl(renderArea.get(), hdrBuffer, regionSampling, grayscale,
+                renderScreenImpl(std::move(renderArea), hdrBuffer, regionSampling, grayscale,
                                  isProtected, captureResults, displayState, layers);
         captureResults.buffer = buffer->getBuffer();
         captureResults.optionalGainMap = gainmapBuffer->getBuffer();
@@ -7672,7 +7672,7 @@
                         })
                         .share();
     } else {
-        renderFuture = renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale,
+        renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale,
                                         isProtected, captureResults, displayState, layers);
     }
 
@@ -7693,7 +7693,8 @@
 }
 
 ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
-        const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+        std::unique_ptr<const RenderArea> renderArea,
+        const std::shared_ptr<renderengine::ExternalTexture>& buffer,
         bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults,
         const std::optional<OutputCompositionState>& displayState,
         const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 824a55a6..a793d50 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -894,7 +894,8 @@
             const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer = nullptr);
 
     ftl::SharedFuture<FenceResult> renderScreenImpl(
-            const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&,
+            std::unique_ptr<const RenderArea> renderArea,
+            const std::shared_ptr<renderengine::ExternalTexture>&,
             bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&,
             const std::optional<OutputCompositionState>& displayState,
             const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c2e8868..2353ef8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -473,7 +473,7 @@
         auto displayState = std::optional{display->getCompositionDisplay()->getState()};
         auto layers = getLayerSnapshotsFn();
 
-        return mFlinger->renderScreenImpl(renderArea.get(), buffer, regionSampling,
+        return mFlinger->renderScreenImpl(std::move(renderArea), buffer, regionSampling,
                                           false /* grayscale */, false /* isProtected */,
                                           captureResults, displayState, layers);
     }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 2bf66ac..7319f1e 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -193,6 +193,8 @@
     MOCK_METHOD(Error, getLuts,
                 (Display, const std::vector<sp<GraphicBuffer>>&,
                  std::vector<aidl::android::hardware::graphics::composer3::Luts>*));
+    MOCK_METHOD4(getLayerPresentFences,
+                 Error(Display, std::vector<Layer>*, std::vector<int>*, std::vector<int64_t>*));
 };
 
 } // namespace Hwc2::mock