Merge "[SF] Adds callback from the VsyncPredictor" into main
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index c40caf5..c86adef 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -353,7 +353,7 @@
     // Now go on and read dexopt lines from stdin and pass them on to otapreopt.
 
     int count = 1;
-    for (std::array<char, 1000> linebuf;
+    for (std::array<char, 10000> linebuf;
          std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) {
         // Subtract one from gcount() since getline() counts the newline.
         std::string line(&linebuf[0], std::cin.gcount() - 1);
diff --git a/data/etc/android.software.opengles.deqp.level-latest.xml b/data/etc/android.software.opengles.deqp.level-latest.xml
index bd15eb6..62bb101 100644
--- a/data/etc/android.software.opengles.deqp.level-latest.xml
+++ b/data/etc/android.software.opengles.deqp.level-latest.xml
@@ -17,5 +17,5 @@
 <!-- This is the standard feature indicating that the device passes OpenGL ES
      dEQP tests associated with the most recent level for this Android version. -->
 <permissions>
-    <feature name="android.software.opengles.deqp.level" version="132580097" />
+    <feature name="android.software.opengles.deqp.level" version="132645633" />
 </permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-latest.xml b/data/etc/android.software.vulkan.deqp.level-latest.xml
index 87be070..0fc12b3 100644
--- a/data/etc/android.software.vulkan.deqp.level-latest.xml
+++ b/data/etc/android.software.vulkan.deqp.level-latest.xml
@@ -17,5 +17,5 @@
 <!-- This is the standard feature indicating that the device passes Vulkan
      dEQP tests associated with the most recent level for this Android version. -->
 <permissions>
-    <feature name="android.software.vulkan.deqp.level" version="132580097" />
+    <feature name="android.software.vulkan.deqp.level" version="132645633" />
 </permissions>
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 2e99495..ee74455 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -98,7 +98,7 @@
     void addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis, float position);
 
     // Adds movement information for all pointers in a MotionEvent, including historical samples.
-    void addMovement(const MotionEvent* event);
+    void addMovement(const MotionEvent& event);
 
     // Returns the velocity of the specified pointer id and axis in position units per second.
     // Returns empty optional if there is insufficient movement information for the pointer, or if
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index f22e90a..8243238 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -30,7 +30,6 @@
 #include <binder/RecordedTransaction.h>
 #include <binder/RpcServer.h>
 #include <pthread.h>
-#include <utils/misc.h>
 
 #include <inttypes.h>
 #include <stdio.h>
@@ -271,7 +270,7 @@
     bool mInheritRt = false;
 
     // for below objects
-    Mutex mLock;
+    RpcMutex mLock;
     std::set<sp<RpcServerLink>> mRpcServerLinks;
     BpBinder::ObjectManager mObjects;
 
@@ -307,7 +306,7 @@
         return PERMISSION_DENIED;
     }
     Extras* e = getOrCreateExtras();
-    AutoMutex lock(e->mLock);
+    RpcMutexUniqueLock lock(e->mLock);
     if (mRecordingOn) {
         LOG(INFO) << "Could not start Binder recording. Another is already in progress.";
         return INVALID_OPERATION;
@@ -337,7 +336,7 @@
         return PERMISSION_DENIED;
     }
     Extras* e = getOrCreateExtras();
-    AutoMutex lock(e->mLock);
+    RpcMutexUniqueLock lock(e->mLock);
     if (mRecordingOn) {
         e->mRecordingFd.reset();
         mRecordingOn = false;
@@ -405,7 +404,7 @@
 
     if (kEnableKernelIpc && mRecordingOn && code != START_RECORDING_TRANSACTION) [[unlikely]] {
         Extras* e = mExtras.load(std::memory_order_acquire);
-        AutoMutex lock(e->mLock);
+        RpcMutexUniqueLock lock(e->mLock);
         if (mRecordingOn) {
             Parcel emptyReply;
             timespec ts;
@@ -452,7 +451,7 @@
     Extras* e = getOrCreateExtras();
     LOG_ALWAYS_FATAL_IF(!e, "no memory");
 
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     return e->mObjects.attach(objectID, object, cleanupCookie, func);
 }
 
@@ -461,7 +460,7 @@
     Extras* e = mExtras.load(std::memory_order_acquire);
     if (!e) return nullptr;
 
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     return e->mObjects.find(objectID);
 }
 
@@ -469,7 +468,7 @@
     Extras* e = mExtras.load(std::memory_order_acquire);
     if (!e) return nullptr;
 
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     return e->mObjects.detach(objectID);
 }
 
@@ -477,7 +476,7 @@
     Extras* e = getOrCreateExtras();
     LOG_ALWAYS_FATAL_IF(!e, "no memory");
 
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     doWithLock();
 }
 
@@ -485,7 +484,7 @@
                                         const void* makeArgs) {
     Extras* e = getOrCreateExtras();
     LOG_ALWAYS_FATAL_IF(!e, "no memory");
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     return e->mObjects.lookupOrCreateWeak(objectID, make, makeArgs);
 }
 
@@ -692,7 +691,7 @@
     auto weakThis = wp<BBinder>::fromExisting(this);
 
     Extras* e = getOrCreateExtras();
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     auto rpcServer = RpcServer::make();
     LOG_ALWAYS_FATAL_IF(rpcServer == nullptr, "RpcServer::make returns null");
     auto link = sp<RpcServerLink>::make(rpcServer, keepAliveBinder, weakThis);
@@ -716,7 +715,7 @@
 void BBinder::removeRpcServerLink(const sp<RpcServerLink>& link) {
     Extras* e = mExtras.load(std::memory_order_acquire);
     if (!e) return;
-    AutoMutex _l(e->mLock);
+    RpcMutexUniqueLock _l(e->mLock);
     (void)e->mRpcServerLinks.erase(link);
 }
 
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 3bc4f92..49038b1 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -23,7 +23,6 @@
 #include <binder/IResultReceiver.h>
 #include <binder/RpcSession.h>
 #include <binder/Stability.h>
-#include <utils/Log.h>
 
 #include <stdio.h>
 
@@ -38,7 +37,7 @@
 
 // ---------------------------------------------------------------------------
 
-Mutex BpBinder::sTrackingLock;
+RpcMutex BpBinder::sTrackingLock;
 std::unordered_map<int32_t, uint32_t> BpBinder::sTrackingMap;
 std::unordered_map<int32_t, uint32_t> BpBinder::sLastLimitCallbackMap;
 int BpBinder::sNumTrackedUids = 0;
@@ -163,7 +162,7 @@
     int32_t trackedUid = -1;
     if (sCountByUidEnabled) {
         trackedUid = IPCThreadState::self()->getCallingUid();
-        AutoMutex _l(sTrackingLock);
+        RpcMutexUniqueLock _l(sTrackingLock);
         uint32_t trackedValue = sTrackingMap[trackedUid];
         if (trackedValue & LIMIT_REACHED_MASK) [[unlikely]] {
             if (sBinderProxyThrottleCreate) {
@@ -276,7 +275,7 @@
 }
 
 bool BpBinder::isDescriptorCached() const {
-    Mutex::Autolock _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     return mDescriptorCache.c_str() != kDescriptorUninit.c_str();
 }
 
@@ -292,7 +291,7 @@
         status_t err = thiz->transact(INTERFACE_TRANSACTION, data, &reply);
         if (err == NO_ERROR) {
             String16 res(reply.readString16());
-            Mutex::Autolock _l(mLock);
+            RpcMutexUniqueLock _l(mLock);
             // mDescriptorCache could have been assigned while the lock was
             // released.
             if (mDescriptorCache.c_str() == kDescriptorUninit.c_str()) mDescriptorCache = res;
@@ -385,7 +384,7 @@
             status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
         }
         if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
-            Mutex::Autolock _l(mLock);
+            RpcMutexUniqueLock _l(mLock);
             ALOGW("Large outgoing transaction of %zu bytes, interface descriptor %s, code %d",
                   data.dataSize(), String8(mDescriptorCache).c_str(), code);
         }
@@ -431,7 +430,7 @@
                         "linkToDeath(): recipient must be non-NULL");
 
     {
-        AutoMutex _l(mLock);
+        RpcMutexUniqueLock _l(mLock);
 
         if (!mObitsSent) {
             if (!mObituaries) {
@@ -467,7 +466,7 @@
         return INVALID_OPERATION;
     }
 
-    AutoMutex _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
 
     if (mObitsSent) {
         return DEAD_OBJECT;
@@ -555,30 +554,30 @@
 
 void* BpBinder::attachObject(const void* objectID, void* object, void* cleanupCookie,
                              object_cleanup_func func) {
-    AutoMutex _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
     return mObjects.attach(objectID, object, cleanupCookie, func);
 }
 
 void* BpBinder::findObject(const void* objectID) const
 {
-    AutoMutex _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     return mObjects.find(objectID);
 }
 
 void* BpBinder::detachObject(const void* objectID) {
-    AutoMutex _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     return mObjects.detach(objectID);
 }
 
 void BpBinder::withLock(const std::function<void()>& doWithLock) {
-    AutoMutex _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     doWithLock();
 }
 
 sp<IBinder> BpBinder::lookupOrCreateWeak(const void* objectID, object_make_func make,
                                          const void* makeArgs) {
-    AutoMutex _l(mLock);
+    RpcMutexUniqueLock _l(mLock);
     return mObjects.lookupOrCreateWeak(objectID, make, makeArgs);
 }
 
@@ -602,7 +601,7 @@
     IPCThreadState* ipc = IPCThreadState::self();
 
     if (mTrackedUid >= 0) {
-        AutoMutex _l(sTrackingLock);
+        RpcMutexUniqueLock _l(sTrackingLock);
         uint32_t trackedValue = sTrackingMap[mTrackedUid];
         if ((trackedValue & COUNTING_VALUE_MASK) == 0) [[unlikely]] {
             ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this,
@@ -702,7 +701,7 @@
 
 uint32_t BpBinder::getBinderProxyCount(uint32_t uid)
 {
-    AutoMutex _l(sTrackingLock);
+    RpcMutexUniqueLock _l(sTrackingLock);
     auto it = sTrackingMap.find(uid);
     if (it != sTrackingMap.end()) {
         return it->second & COUNTING_VALUE_MASK;
@@ -717,7 +716,7 @@
 
 void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts)
 {
-    AutoMutex _l(sTrackingLock);
+    RpcMutexUniqueLock _l(sTrackingLock);
     uids.setCapacity(sTrackingMap.size());
     counts.setCapacity(sTrackingMap.size());
     for (const auto& it : sTrackingMap) {
@@ -731,12 +730,12 @@
 void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); }
 
 void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) {
-    AutoMutex _l(sTrackingLock);
+    RpcMutexUniqueLock _l(sTrackingLock);
     sLimitCallback = cb;
 }
 
 void BpBinder::setBinderProxyCountWatermarks(int high, int low) {
-    AutoMutex _l(sTrackingLock);
+    RpcMutexUniqueLock _l(sTrackingLock);
     sBinderProxyCountHighWatermark = high;
     sBinderProxyCountLowWatermark = low;
 }
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index c6e4fb3..7ae616e 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -19,8 +19,6 @@
 
 #include <binder/ProcessState.h>
 
-#include <utils/misc.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
index 2780bd4..dea2603 100644
--- a/libs/binder/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -15,7 +15,6 @@
  */
 
 #define LOG_TAG "IInterface"
-#include <utils/Log.h>
 #include <binder/IInterface.h>
 
 namespace android {
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index cd92217..60ece72 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -18,7 +18,6 @@
 
 #include <binder/IResultReceiver.h>
 
-#include <utils/Log.h>
 #include <binder/Parcel.h>
 #include <utils/String8.h>
 
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 6034f2b..fe566fc 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -200,7 +200,7 @@
 }
 
 bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure) {
-    static Mutex gPermissionControllerLock;
+    static std::mutex gPermissionControllerLock;
     static sp<IPermissionController> gPermissionController;
 
     sp<IPermissionController> pc;
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 5b1cb7e..95bdbb4 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -155,7 +155,7 @@
     void     dump_l(String8& res, const char* what) const;
 
     static const int    kMemoryAlign;
-    mutable Mutex       mLock;
+    mutable std::mutex mLock;
     LinkedList<chunk_t> mList;
     size_t              mHeapSize;
 };
@@ -305,14 +305,14 @@
 
 size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
 {
-    Mutex::Autolock _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
     ssize_t offset = alloc(size, flags);
     return offset;
 }
 
 status_t SimpleBestFitAllocator::deallocate(size_t offset)
 {
-    Mutex::Autolock _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
     chunk_t const * const freed = dealloc(offset);
     if (freed) {
         return NO_ERROR;
@@ -420,7 +420,7 @@
 
 void SimpleBestFitAllocator::dump(const char* what) const
 {
-    Mutex::Autolock _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
     dump_l(what);
 }
 
@@ -434,7 +434,7 @@
 void SimpleBestFitAllocator::dump(String8& result,
         const char* what) const
 {
-    Mutex::Autolock _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
     dump_l(result, what);
 }
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a3ff7d2..6d2e12b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "Parcel"
 //#define LOG_NDEBUG 0
 
+#include <endian.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -43,11 +44,8 @@
 #ifndef BINDER_DISABLE_BLOB
 #include <cutils/ashmem.h>
 #endif
-#include <utils/Flattenable.h>
-#include <utils/Log.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
-#include <utils/misc.h>
 
 #include "OS.h"
 #include "RpcState.h"
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 8ec4af9..58203c1 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -189,7 +189,7 @@
 
 void ProcessState::startThreadPool()
 {
-    AutoMutex _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
     if (!mThreadPoolStarted) {
         if (mMaxThreads == 0) {
             // see also getThreadPoolMaxTotalThreadCount
@@ -203,7 +203,7 @@
 
 bool ProcessState::becomeContextManager()
 {
-    AutoMutex _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
 
     flat_binder_object obj {
         .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
@@ -310,7 +310,7 @@
 {
     sp<IBinder> result;
 
-    AutoMutex _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
 
     if (handle == 0 && the_context_object != nullptr) return the_context_object;
 
@@ -374,7 +374,7 @@
 
 void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
 {
-    AutoMutex _l(mLock);
+    std::unique_lock<std::mutex> _l(mLock);
 
     handle_entry* e = lookupHandleLocked(handle);
 
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 07ab093..1011571 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -30,7 +30,6 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <log/log.h>
-#include <utils/Compat.h>
 
 #include "BuildFlags.h"
 #include "FdTrigger.h"
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index fa8f2b5..c8aff63 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -33,7 +33,6 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/Stability.h>
-#include <utils/Compat.h>
 #include <utils/String8.h>
 
 #include "BuildFlags.h"
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 26a2f4f..749c2f8 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -412,10 +412,8 @@
             return false;
         }
 #else
-        // TODO(b/305983144)
-        // don't restrict on other platforms, though experimental should
-        // only really be used for testing, we don't have a good way to see
-        // what is shipping outside of Android
+        ALOGE("Cannot use experimental RPC binder protocol outside of Android.");
+        return false;
 #endif
     } else if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT) {
         ALOGE("Cannot use RPC binder protocol version %u which is unknown (current protocol "
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index dd632c0..8942c31 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -22,6 +22,19 @@
 #include <log/log.h>
 #include <utils/Errors.h>
 
+/* TEMP_FAILURE_RETRY is not available on macOS and Trusty. */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp)                \
+    ({                                         \
+        __typeof__(exp) _rc;                   \
+        do {                                   \
+            _rc = (exp);                       \
+        } while (_rc == -1 && errno == EINTR); \
+        _rc;                                   \
+    })
+#endif
+
 #define TEST_AND_RETURN(value, expr)            \
     do {                                        \
         if (!(expr)) {                          \
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 28fb9f1..d78ea0d 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -18,7 +18,7 @@
 
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
-#include <utils/Mutex.h>
+#include <binder/RpcThreads.h>
 
 #include <map>
 #include <optional>
@@ -193,7 +193,7 @@
             void                reportOneDeath(const Obituary& obit);
             bool                isDescriptorCached() const;
 
-    mutable Mutex               mLock;
+    mutable RpcMutex            mLock;
             volatile int32_t    mAlive;
             volatile int32_t    mObitsSent;
             Vector<Obituary>*   mObituaries;
@@ -201,7 +201,7 @@
     mutable String16            mDescriptorCache;
             int32_t             mTrackedUid;
 
-    static Mutex                                sTrackingLock;
+    static RpcMutex                             sTrackingLock;
     static std::unordered_map<int32_t,uint32_t> sTrackingMap;
     static int                                  sNumTrackedUids;
     static std::atomic_bool                     sCountByUidEnabled;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 98d12bb..6961abc 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -33,7 +33,6 @@
 #include <utils/RefBase.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
-#include <utils/Flattenable.h>
 
 #include <binder/IInterface.h>
 #include <binder/Parcelable.h>
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 9dc370b..3672702 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -17,13 +17,13 @@
 #pragma once
 
 #include <binder/IBinder.h>
-#include <utils/KeyedVector.h>
-#include <utils/Mutex.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 
 #include <pthread.h>
 
+#include <mutex>
+
 // ---------------------------------------------------------------------------
 namespace android {
 
@@ -178,7 +178,7 @@
     // Time when thread pool was emptied
     int64_t mStarvationStartTimeMs;
 
-    mutable Mutex mLock; // protects everything below.
+    mutable std::mutex mLock; // protects everything below.
 
     Vector<handle_entry> mHandleToObject;
 
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 341e9ce..659943a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -40,6 +40,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <utils/Flattenable.h>
 
 #include <linux/sched.h>
 #include <sys/epoll.h>
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 786fab8..c3070dd 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -74,8 +74,7 @@
 #ifdef __ANDROID__
     return base::GetProperty("ro.build.version.codename", "") != "REL";
 #else
-    // TODO(b/305983144): restrict on other platforms
-    return true;
+    return false;
 #endif
 }
 
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 1c13866..cbbbe74 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -28,6 +28,7 @@
 #include <gtest/gtest.h>
 #pragma clang diagnostic pop
 
+#include <utils/Flattenable.h>
 #include <utils/LightRefBase.h>
 #include <utils/NativeHandle.h>
 
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 383795e..fe79f8e 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -32,7 +32,11 @@
     host_supported: true,
 
     fuzz_config: {
-        cc: ["smoreland@google.com"],
+        cc: [
+            "smoreland@google.com",
+            "waghpawan@google.com",
+        ],
+        use_for_presubmit: true,
     },
 
     srcs: [
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 416ffad..ffeca2d 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -25,6 +25,7 @@
 #include <binder/ParcelableHolder.h>
 #include <binder/PersistableBundle.h>
 #include <binder/Status.h>
+#include <utils/Flattenable.h>
 
 #include "../../Utils.h"
 
diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
index e494366..f3006cd 100644
--- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
@@ -35,7 +35,7 @@
     if (transaction.has_value()) {
         intermediateFile = std::tmpfile();
 
-        android::base::unique_fd fdForWriting(fileno(intermediateFile));
+        android::base::unique_fd fdForWriting(dup(fileno(intermediateFile)));
         auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting);
 
         std::fclose(intermediateFile);
diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp
index d4605ea..3fe71ce 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -34,5 +34,7 @@
         "libbase",
         "liblog",
     ],
+    static_libs: ["libguiflags"],
     export_include_dirs: ["include"],
+    export_static_lib_headers: ["libguiflags"],
 }
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index ed5d5c1..394a000 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -575,17 +575,23 @@
         return mAngleNamespace;
     }
 
-    if (mAnglePath.empty() && !mShouldUseSystemAngle) {
-        ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace");
+    // If ANGLE path is not set, it means ANGLE should not be used for this process;
+    // or if ANGLE path is set and set to use system ANGLE, then a namespace is not needed
+    // because:
+    //     1) if the default OpenGL ES driver is already ANGLE, then the loader will skip;
+    //     2) if the default OpenGL ES driver is native, then there's no symbol conflict;
+    //     3) if there's no OpenGL ES driver is preloaded, then there's no symbol conflict.
+    if (mAnglePath.empty() || mShouldUseSystemAngle) {
+        ALOGV("mAnglePath is empty or use system ANGLE, abort creating ANGLE namespace");
         return nullptr;
     }
 
     // Construct the search paths for system ANGLE.
     const char* const defaultLibraryPaths =
 #if defined(__LP64__)
-            "/vendor/lib64/egl:/system/lib64/egl";
+            "/vendor/lib64/egl:/system/lib64";
 #else
-            "/vendor/lib/egl:/system/lib/egl";
+            "/vendor/lib/egl:/system/lib";
 #endif
 
     // If the application process will run on top of system ANGLE, construct the namespace
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index 47607a0..9ebaf16 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -104,7 +104,7 @@
         GL_UPDATED = 2,
         VULKAN = 3,
         VULKAN_UPDATED = 4,
-        ANGLE = 5,
+        ANGLE = 5, // cover both system ANGLE and ANGLE APK
     };
 
     enum Stats {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index f17a654..c84ee1f 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -20,6 +20,25 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+aconfig_declarations {
+    name: "libgui_flags",
+    package: "com.android.graphics.libgui.flags",
+    srcs: ["libgui_flags.aconfig"],
+}
+
+cc_aconfig_library {
+    name: "libguiflags",
+    host_supported: true,
+    vendor_available: true,
+    min_sdk_version: "29",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    aconfig_declarations: "libgui_flags",
+}
+
 cc_library_headers {
     name: "libgui_headers",
     vendor_available: true,
@@ -36,6 +55,8 @@
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.bufferqueue@2.0",
     ],
+    static_libs: ["libguiflags"],
+    export_static_lib_headers: ["libguiflags"],
     min_sdk_version: "29",
     // TODO(b/218719284) can media use be constrained to libgui_bufferqueue_static?
     apex_available: [
@@ -192,19 +213,6 @@
     },
 }
 
-aconfig_declarations {
-    name: "libgui_flags",
-    package: "com.android.graphics.libgui.flags",
-    srcs: ["libgui_flags.aconfig"],
-}
-
-cc_aconfig_library {
-    name: "libguiflags",
-    host_supported: true,
-    vendor_available: true,
-    aconfig_declarations: "libgui_flags",
-}
-
 filegroup {
     name: "libgui-sources",
     srcs: [
@@ -265,6 +273,9 @@
         "libbinder",
         "libGLESv2",
     ],
+    export_static_lib_headers: [
+        "libguiflags",
+    ],
 }
 
 cc_library_shared {
@@ -460,6 +471,7 @@
     static_libs: [
         "libgtest",
         "libgmock",
+        "libguiflags",
     ],
 
     srcs: [
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dd0a028..8d0331e 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -26,7 +26,7 @@
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
 #include <gui/BufferQueueProducer.h>
-#include <gui/Flags.h>
+
 #include <gui/FrameRateUtils.h>
 #include <gui/GLConsumer.h>
 #include <gui/IProducerListener.h>
@@ -41,8 +41,6 @@
 #include <android-base/thread_annotations.h>
 #include <chrono>
 
-#include <com_android_graphics_libgui_flags.h>
-
 using namespace com::android::graphics::libgui;
 using namespace std::chrono_literals;
 
@@ -144,7 +142,7 @@
     }
 }
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
 void BLASTBufferItemConsumer::onSetFrameRate(float frameRate, int8_t compatibility,
                                              int8_t changeFrameRateStrategy) {
     sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index ab0f6d2..b0f6e69 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -22,7 +22,6 @@
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
 #include <gui/BufferQueueProducer.h>
-#include <gui/Flags.h>
 
 namespace android {
 
@@ -99,7 +98,7 @@
     }
 }
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
 void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t compatibility,
                                                         int8_t changeFrameRateStrategy) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 67dff6d..19693e3 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -32,7 +32,7 @@
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueCore.h>
 #include <gui/BufferQueueProducer.h>
-#include <gui/Flags.h>
+
 #include <gui/FrameRateUtils.h>
 #include <gui/GLConsumer.h>
 #include <gui/IConsumerListener.h>
@@ -1753,7 +1753,7 @@
     return NO_ERROR;
 }
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
 status_t BufferQueueProducer::setFrameRate(float frameRate, int8_t compatibility,
                                            int8_t changeFrameRateStrategy) {
     ATRACE_CALL();
diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp
index 6993bfa..11524e2 100644
--- a/libs/gui/FrameRateUtils.cpp
+++ b/libs/gui/FrameRateUtils.cpp
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-#include <gui/Flags.h>
 #include <gui/FrameRateUtils.h>
 #include <system/window.h>
 #include <utils/Log.h>
 
 #include <cmath>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
+using namespace com::android::graphics::libgui;
 // Returns true if the frameRate is valid.
 //
 // @param frameRate the frame rate in Hz
@@ -53,7 +55,7 @@
             changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) {
             ALOGE("%s failed - invalid change frame rate strategy value %d", functionName,
                   changeFrameRateStrategy);
-            if (FLAG_BQ_SET_FRAME_RATE) {
+            if (flags::bq_setframerate()) {
                 return false;
             }
         }
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index d0c09e4..e81c098 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -28,7 +28,7 @@
 #include <binder/IInterface.h>
 
 #include <gui/BufferQueueDefs.h>
-#include <gui/Flags.h>
+
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
@@ -763,7 +763,7 @@
         }
         return result;
     }
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     virtual status_t setFrameRate(float frameRate, int8_t compatibility,
                                   int8_t changeFrameRateStrategy) override {
         Parcel data, reply;
@@ -973,7 +973,7 @@
     return INVALID_OPERATION;
 }
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
 status_t IGraphicBufferProducer::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
                                               int8_t /*changeFrameRateStrategy*/) {
     // No-op for IGBP other than BufferQueue.
@@ -1522,7 +1522,7 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
         case SET_FRAME_RATE: {
             CHECK_INTERFACE(IGraphicBuffer, data, reply);
             float frameRate = data.readFloat();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a87f053..07a0cfe 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,7 +43,7 @@
 
 #include <gui/AidlStatusUtil.h>
 #include <gui/BufferItem.h>
-#include <gui/Flags.h>
+
 #include <gui/IProducerListener.h>
 
 #include <gui/ISurfaceComposer.h>
@@ -2571,7 +2571,7 @@
 
 status_t Surface::setFrameRate(float frameRate, int8_t compatibility,
                                int8_t changeFrameRateStrategy) {
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     if (flags::bq_setframerate()) {
         status_t err = mGraphicBufferProducer->setFrameRate(frameRate, compatibility,
                                                             changeFrameRateStrategy);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 02d7c4d..892215e 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -19,7 +19,7 @@
 
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
-#include <gui/Flags.h>
+
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/SurfaceComposerClient.h>
 
@@ -31,6 +31,8 @@
 #include <thread>
 #include <queue>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
 
 class BLASTBufferQueue;
@@ -59,7 +61,7 @@
 
 protected:
     void onSidebandStreamChanged() override EXCLUDES(mMutex);
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     void onSetFrameRate(float frameRate, int8_t compatibility,
                         int8_t changeFrameRateStrategy) override;
 #endif
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index 2756277..0948c4d0 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -19,11 +19,13 @@
 
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueDefs.h>
-#include <gui/Flags.h>
+
 #include <gui/IConsumerListener.h>
 #include <gui/IGraphicBufferConsumer.h>
 #include <gui/IGraphicBufferProducer.h>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
 
 class BufferQueue {
@@ -70,7 +72,7 @@
         void addAndGetFrameTimestamps(
                 const NewFrameEventsEntry* newTimestamps,
                 FrameEventHistoryDelta* outDelta) override;
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
         void onSetFrameRate(float frameRate, int8_t compatibility,
                             int8_t changeFrameRateStrategy) override;
 #endif
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 38805d0..de47483 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -18,7 +18,7 @@
 #define ANDROID_GUI_BUFFERQUEUEPRODUCER_H
 
 #include <gui/BufferQueueDefs.h>
-#include <gui/Flags.h>
+
 #include <gui/IGraphicBufferProducer.h>
 
 namespace android {
@@ -202,7 +202,7 @@
 
     // See IGraphicBufferProducer::setAutoPrerotation
     virtual status_t setAutoPrerotation(bool autoPrerotation);
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     // See IGraphicBufferProducer::setFrameRate
     status_t setFrameRate(float frameRate, int8_t compatibility,
                           int8_t changeFrameRateStrategy) override;
diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h
deleted file mode 100644
index a2cff56..0000000
--- a/libs/gui/include/gui/Flags.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2023 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
-
-// TODO(281695725): replace this with build time flags, whenever they are available
-#ifndef FLAG_BQ_SET_FRAME_RATE
-#define FLAG_BQ_SET_FRAME_RATE false
-#endif
\ No newline at end of file
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index e183bf2..51d3959 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -19,13 +19,13 @@
 #include <binder/IInterface.h>
 #include <binder/SafeInterface.h>
 
-#include <gui/Flags.h>
-
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
 #include <cstdint>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
 
 class BufferItem;
@@ -93,7 +93,7 @@
     virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/,
                                           FrameEventHistoryDelta* /*outDelta*/) {}
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     // Notifies the consumer of a setFrameRate call from the producer side.
     virtual void onSetFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
                                 int8_t /*changeFrameRateStrategy*/) {}
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 3562906..7639e70 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -31,7 +31,6 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
-#include <gui/Flags.h>
 #include <gui/FrameTimestamps.h>
 #include <gui/HdrMetadata.h>
 
@@ -42,6 +41,8 @@
 #include <optional>
 #include <vector>
 
+#include <com_android_graphics_libgui_flags.h>
+
 namespace android {
 // ----------------------------------------------------------------------------
 
@@ -677,7 +678,7 @@
     // the width and height used for dequeueBuffer will be additionally swapped.
     virtual status_t setAutoPrerotation(bool autoPrerotation);
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     // Sets the apps intended frame rate.
     virtual status_t setFrameRate(float frameRate, int8_t compatibility,
                                   int8_t changeFrameRateStrategy);
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 38c0eed..6dcd501 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -21,7 +21,7 @@
         "-Wall",
         "-Werror",
         "-Wno-extra",
-        "-DFLAG_BQ_SET_FRAME_RATE=true",
+        "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_SETFRAMERATE=true",
     ],
 
     srcs: [
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 17aa5f1..1410c7d 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1266,9 +1266,7 @@
 }
 
 TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) {
-    if (flags::bq_setframerate()) {
-        ASSERT_EQ(true, FLAG_BQ_SET_FRAME_RATE);
-    }
+    ASSERT_EQ(flags::bq_setframerate(), COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE));
 }
 
 struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e7b1232..86ced2c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -1341,7 +1341,7 @@
                 newFrame->mRefreshes[0].mGpuCompositionDone.mFenceTime :
                 FenceTime::NO_FENCE;
         // HWC2 releases the previous buffer after a new latch just before
-        // calling postComposition.
+        // calling onCompositionPresented.
         if (oldFrame != nullptr) {
             mCfeh->addRelease(nOldFrame, oldFrame->kDequeueReadyTime,
                     std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 116b778..613a0df 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -275,10 +275,10 @@
     }
 }
 
-void VelocityTracker::addMovement(const MotionEvent* event) {
+void VelocityTracker::addMovement(const MotionEvent& event) {
     // Stores data about which axes to process based on the incoming motion event.
     std::set<int32_t> axesToProcess;
-    int32_t actionMasked = event->getActionMasked();
+    int32_t actionMasked = event.getActionMasked();
 
     switch (actionMasked) {
         case AMOTION_EVENT_ACTION_DOWN:
@@ -291,7 +291,7 @@
             // Start a new movement trace for a pointer that just went down.
             // We do this on down instead of on up because the client may want to query the
             // final velocity for a pointer that just went up.
-            clearPointer(event->getPointerId(event->getActionIndex()));
+            clearPointer(event.getPointerId(event.getActionIndex()));
             axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
             break;
         }
@@ -300,8 +300,14 @@
             axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
             break;
         case AMOTION_EVENT_ACTION_POINTER_UP:
+            if (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) {
+                clearPointer(event.getPointerId(event.getActionIndex()));
+                return;
+            }
+            // Continue to ACTION_UP to ensure that the POINTER_STOPPED logic is triggered.
+            [[fallthrough]];
         case AMOTION_EVENT_ACTION_UP: {
-            std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime);
+            std::chrono::nanoseconds delaySinceLastEvent(event.getEventTime() - mLastEventTime);
             if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) {
                 ALOGD_IF(DEBUG_VELOCITY,
                          "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.",
@@ -325,21 +331,26 @@
         case AMOTION_EVENT_ACTION_SCROLL:
             axesToProcess.insert(AMOTION_EVENT_AXIS_SCROLL);
             break;
+        case AMOTION_EVENT_ACTION_CANCEL: {
+            clear();
+            return;
+        }
+
         default:
             // Ignore all other actions.
             return;
     }
 
-    const size_t historySize = event->getHistorySize();
+    const size_t historySize = event.getHistorySize();
     for (size_t h = 0; h <= historySize; h++) {
-        const nsecs_t eventTime = event->getHistoricalEventTime(h);
-        for (size_t i = 0; i < event->getPointerCount(); i++) {
-            if (event->isResampled(i, h)) {
+        const nsecs_t eventTime = event.getHistoricalEventTime(h);
+        for (size_t i = 0; i < event.getPointerCount(); i++) {
+            if (event.isResampled(i, h)) {
                 continue; // skip resampled samples
             }
-            const int32_t pointerId = event->getPointerId(i);
+            const int32_t pointerId = event.getPointerId(i);
             for (int32_t axis : axesToProcess) {
-                const float position = event->getHistoricalAxisValue(axis, i, h);
+                const float position = event.getHistoricalAxisValue(axis, i, h);
                 addMovement(eventTime, pointerId, axis, position);
             }
         }
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 978a80f..3672387 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -48,3 +48,17 @@
   description: "Enable additional palm rejection on touchpad while typing"
   bug: "301055381"
 }
+
+flag {
+  name: "remove_app_switch_drops"
+  namespace: "input"
+  description: "Remove the logic of dropping events due to pending app switch"
+  bug: "284808102"
+}
+
+flag {
+  name: "disable_reject_touch_on_stylus_hover"
+  namespace: "input"
+  description: "Disable touch rejection when the stylus hovers the screen"
+  bug: "301216095"
+}
diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs
index bbc6d98..5f05a0f 100644
--- a/libs/input/rust/input_verifier.rs
+++ b/libs/input/rust/input_verifier.rs
@@ -118,18 +118,17 @@
 
         match action.into() {
             MotionAction::Down => {
+                if self.touching_pointer_ids_by_device.contains_key(&device_id) {
+                    return Err(format!(
+                        "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
+                        self.name, device_id, self.touching_pointer_ids_by_device
+                    ));
+                }
                 let it = self
                     .touching_pointer_ids_by_device
                     .entry(device_id)
                     .or_insert_with(HashSet::new);
-                let pointer_id = pointer_properties[0].id;
-                if it.contains(&pointer_id) {
-                    return Err(format!(
-                        "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
-                        self.name, device_id, it
-                    ));
-                }
-                it.insert(pointer_id);
+                it.insert(pointer_properties[0].id);
             }
             MotionAction::PointerDown { action_index } => {
                 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
@@ -353,6 +352,56 @@
     }
 
     #[test]
+    fn two_pointer_stream() {
+        let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
+        let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                Source::Touchscreen,
+                input_bindgen::AMOTION_EVENT_ACTION_DOWN,
+                &pointer_properties,
+                MotionFlags::empty(),
+            )
+            .is_ok());
+        // POINTER 1 DOWN
+        let two_pointer_properties =
+            Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                Source::Touchscreen,
+                input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
+                    | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                &two_pointer_properties,
+                MotionFlags::empty(),
+            )
+            .is_ok());
+        // POINTER 0 UP
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                Source::Touchscreen,
+                input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP
+                    | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                &two_pointer_properties,
+                MotionFlags::empty(),
+            )
+            .is_ok());
+        // ACTION_UP for pointer id=1
+        let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]);
+        assert!(verifier
+            .process_movement(
+                DeviceId(1),
+                Source::Touchscreen,
+                input_bindgen::AMOTION_EVENT_ACTION_UP,
+                &pointer_1_properties,
+                MotionFlags::empty(),
+            )
+            .is_ok());
+    }
+
+    #[test]
     fn multi_device_stream() {
         let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
         let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 1c8ec90..f9ca280 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -229,41 +229,23 @@
     return events;
 }
 
-static std::optional<float> computePlanarVelocity(
-        const VelocityTracker::Strategy strategy,
-        const std::vector<PlanarMotionEventEntry>& motions, int32_t axis,
-        uint32_t pointerId = DEFAULT_POINTER_ID) {
+static std::optional<float> computeVelocity(const VelocityTracker::Strategy strategy,
+                                            const std::vector<MotionEvent>& events, int32_t axis,
+                                            uint32_t pointerId = DEFAULT_POINTER_ID) {
     VelocityTracker vt(strategy);
 
-    std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
-    for (MotionEvent event : events) {
-        vt.addMovement(&event);
+    for (const MotionEvent& event : events) {
+        vt.addMovement(event);
     }
 
     return vt.getVelocity(axis, pointerId);
 }
 
-static std::vector<MotionEvent> createMotionEventStream(
-        int32_t axis, const std::vector<std::pair<std::chrono::nanoseconds, float>>& motion) {
-    switch (axis) {
-        case AMOTION_EVENT_AXIS_SCROLL:
-            return createAxisScrollMotionEventStream(motion);
-        default:
-            ADD_FAILURE() << "Axis " << axis << " is not supported";
-            return {};
-    }
-}
-
-static std::optional<float> computeVelocity(
+static std::optional<float> computePlanarVelocity(
         const VelocityTracker::Strategy strategy,
-        const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions, int32_t axis) {
-    VelocityTracker vt(strategy);
-
-    for (const MotionEvent& event : createMotionEventStream(axis, motions)) {
-        vt.addMovement(&event);
-    }
-
-    return vt.getVelocity(axis, DEFAULT_POINTER_ID);
+        const std::vector<PlanarMotionEventEntry>& motions, int32_t axis, uint32_t pointerId) {
+    std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
+    return computeVelocity(strategy, events, axis, pointerId);
 }
 
 static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
@@ -277,23 +259,23 @@
         const VelocityTracker::Strategy strategy,
         const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions,
         std::optional<float> targetVelocity) {
-    checkVelocity(computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL), targetVelocity);
+    std::vector<MotionEvent> events = createAxisScrollMotionEventStream(motions);
+    checkVelocity(computeVelocity(strategy, events, AMOTION_EVENT_AXIS_SCROLL), targetVelocity);
     // The strategy LSQ2 is not compatible with AXIS_SCROLL. In those situations, we should fall
     // back to a strategy that supports differential axes.
-    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, motions,
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events,
                                   AMOTION_EVENT_AXIS_SCROLL),
                   targetVelocity);
 }
 
 static void computeAndCheckQuadraticVelocity(const std::vector<PlanarMotionEventEntry>& motions,
                                              float velocity) {
-    VelocityTracker vt(VelocityTracker::Strategy::LSQ2);
-    std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
-    for (MotionEvent event : events) {
-        vt.addMovement(&event);
-    }
-    std::optional<float> velocityX = vt.getVelocity(AMOTION_EVENT_AXIS_X, 0);
-    std::optional<float> velocityY = vt.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
+    std::optional<float> velocityX =
+            computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+                                  DEFAULT_POINTER_ID);
+    std::optional<float> velocityY =
+            computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+                                  DEFAULT_POINTER_ID);
     ASSERT_TRUE(velocityX);
     ASSERT_TRUE(velocityY);
 
@@ -330,12 +312,14 @@
                                                    {30ms, {{6, 20}}},
                                                    {40ms, {{10, 30}}}};
 
-    EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X),
+    EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+                                    DEFAULT_POINTER_ID),
               computePlanarVelocity(VelocityTracker::Strategy::DEFAULT, motions,
-                                    AMOTION_EVENT_AXIS_X));
-    EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y),
+                                    AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID));
+    EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+                                    DEFAULT_POINTER_ID),
               computePlanarVelocity(VelocityTracker::Strategy::DEFAULT, motions,
-                                    AMOTION_EVENT_AXIS_Y));
+                                    AMOTION_EVENT_AXIS_Y, DEFAULT_POINTER_ID));
 }
 
 TEST_F(VelocityTrackerTest, TestComputedVelocity) {
@@ -431,7 +415,7 @@
     VelocityTracker vt(VelocityTracker::Strategy::IMPULSE);
     std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
     for (const MotionEvent& event : events) {
-        vt.addMovement(&event);
+        vt.addMovement(event);
     }
 
     float maxFloat = std::numeric_limits<float>::max();
@@ -509,6 +493,89 @@
     computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 500);
 }
 
+/**
+ * When the stream is terminated with ACTION_CANCEL, the resulting velocity should be 0.
+ */
+TEST_F(VelocityTrackerTest, ActionCancelResultsInZeroVelocity) {
+    std::vector<PlanarMotionEventEntry> motions = {
+            {0ms, {{0, 0}}},    // DOWN
+            {10ms, {{5, 10}}},  // MOVE
+            {20ms, {{10, 20}}}, // MOVE
+            {20ms, {{10, 20}}}, // ACTION_UP
+    };
+    std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
+    // By default, `createTouchMotionEventStream` produces an event stream that terminates with
+    // ACTION_UP. We need to manually change it to ACTION_CANCEL.
+    MotionEvent& lastEvent = events.back();
+    lastEvent.setAction(AMOTION_EVENT_ACTION_CANCEL);
+    lastEvent.setFlags(lastEvent.getFlags() | AMOTION_EVENT_FLAG_CANCELED);
+    const int32_t pointerId = lastEvent.getPointerId(0);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_X,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_Y,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_X,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_Y,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+}
+
+/**
+ * When the stream is terminated with ACTION_CANCEL, the resulting velocity should be 0.
+ */
+TEST_F(VelocityTrackerTest, ActionPointerCancelResultsInZeroVelocityForThatPointer) {
+    std::vector<PlanarMotionEventEntry> motions = {
+            {0ms, {{0, 5}, {NAN, NAN}}},    // DOWN
+            {0ms, {{0, 5}, {10, 15}}},      // POINTER_DOWN
+            {10ms, {{5, 10}, {15, 20}}},    // MOVE
+            {20ms, {{10, 15}, {20, 25}}},   // MOVE
+            {30ms, {{10, 15}, {20, 25}}},   // POINTER_UP
+            {30ms, {{10, 15}, {NAN, NAN}}}, // UP
+    };
+    std::vector<MotionEvent> events = createTouchMotionEventStream(motions);
+    // Cancel the lifting pointer of the ACTION_POINTER_UP event
+    MotionEvent& pointerUpEvent = events.rbegin()[1];
+    pointerUpEvent.setFlags(pointerUpEvent.getFlags() | AMOTION_EVENT_FLAG_CANCELED);
+    const int32_t pointerId = pointerUpEvent.getPointerId(pointerUpEvent.getActionIndex());
+    // Double check the stream
+    ASSERT_EQ(1, pointerId);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP, pointerUpEvent.getActionMasked());
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, events.back().getActionMasked());
+
+    // Ensure the velocity of the lifting pointer is zero
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_X,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_Y,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_X,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_Y,
+                                  pointerId),
+                  /*targetVelocity*/ std::nullopt);
+
+    // The remaining pointer should have the correct velocity.
+    const int32_t remainingPointerId = events.back().getPointerId(0);
+    ASSERT_EQ(0, remainingPointerId);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_X,
+                                  remainingPointerId),
+                  /*targetVelocity*/ 500);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_Y,
+                                  remainingPointerId),
+                  /*targetVelocity*/ 500);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_X,
+                                  remainingPointerId),
+                  /*targetVelocity*/ 500);
+    checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_Y,
+                                  remainingPointerId),
+                  /*targetVelocity*/ 500);
+}
 
 /**
  * ================== VelocityTracker tests generated by recording real events =====================
@@ -1336,9 +1403,10 @@
             {40ms, 100},
     };
 
-    EXPECT_EQ(computeVelocity(VelocityTracker::Strategy::IMPULSE, motions,
+    std::vector<MotionEvent> events = createAxisScrollMotionEventStream(motions);
+    EXPECT_EQ(computeVelocity(VelocityTracker::Strategy::IMPULSE, events,
                               AMOTION_EVENT_AXIS_SCROLL),
-              computeVelocity(VelocityTracker::Strategy::DEFAULT, motions,
+              computeVelocity(VelocityTracker::Strategy::DEFAULT, events,
                               AMOTION_EVENT_AXIS_SCROLL));
 }
 
diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
index 32fb350..099f47d 100644
--- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
+++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
@@ -19,7 +19,7 @@
 #include <android/hardware_buffer.h>
 #include <gui/BufferQueueDefs.h>
 #include <gui/ConsumerBase.h>
-#include <gui/Flags.h>
+
 #include <gui/IGraphicBufferProducer.h>
 #include <sys/cdefs.h>
 #include <system/graphics.h>
@@ -352,7 +352,7 @@
     /**
      * onSetFrameRate Notifies the consumer of a setFrameRate call from the producer side.
      */
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
     void onSetFrameRate(float frameRate, int8_t compatibility,
                         int8_t changeFrameRateStrategy) override;
 #endif
diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index c2535e0..3a09204 100644
--- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -515,7 +515,7 @@
     }
 }
 
-#if FLAG_BQ_SET_FRAME_RATE
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)
 void SurfaceTexture::onSetFrameRate(float frameRate, int8_t compatibility,
                                     int8_t changeFrameRateStrategy) {
     SFT_LOGV("onSetFrameRate: %.2f", frameRate);
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
index 0eeca54..86dcaef 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -20,6 +20,12 @@
     ],
 }
 
+filegroup {
+    name: "framework-permission-aidl-filegroup",
+    srcs: ["aidl/android/**/*.aidl"],
+    path: "aidl",
+}
+
 cc_library {
     name: "libpermission",
     host_supported: true,
@@ -35,6 +41,7 @@
         "-Werror",
     ],
     srcs: [
+        ":framework-permission-aidl-filegroup",
         "AppOpsManager.cpp",
         "IAppOpsCallback.cpp",
         "IAppOpsService.cpp",
diff --git a/libs/permission/AppOpsManager.cpp b/libs/permission/AppOpsManager.cpp
index 6959274..b407d02 100644
--- a/libs/permission/AppOpsManager.cpp
+++ b/libs/permission/AppOpsManager.cpp
@@ -31,6 +31,9 @@
 
 namespace android {
 
+using ::android::String16;
+using ::android::String8;
+
 static const sp<IBinder>& getClientId() {
     static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER;
     static sp<IBinder> gClientId;
@@ -43,6 +46,11 @@
     return gClientId;
 }
 
+
+static std::string getString(const String16& stringToConvert) {
+  return std::string(String8(stringToConvert).c_str());
+}
+
 AppOpsManager::AppOpsManager()
 {
 }
@@ -78,9 +86,14 @@
 int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
 {
     sp<IAppOpsService> service = getService();
-    return service != nullptr
-            ? service->checkOperation(op, uid, callingPackage)
-            : AppOpsManager::MODE_IGNORED;
+    if (service == nullptr) {
+        return AppOpsManager::MODE_IGNORED;
+    }
+    AttributionSourceState attributionSourceState;
+    attributionSourceState.uid = uid;
+    attributionSourceState.packageName = getString(callingPackage);
+
+    return service->checkOperationWithState(op, attributionSourceState);
 }
 
 int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
@@ -99,12 +112,18 @@
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
         const std::optional<String16>& attributionTag, const String16& message) {
     sp<IAppOpsService> service = getService();
-    int32_t mode = service != nullptr
-            ? service->noteOperation(op, uid, callingPackage, attributionTag,
-                    shouldCollectNotes(op), message, uid == AID_SYSTEM)
-            : AppOpsManager::MODE_IGNORED;
+    if (service == nullptr) {
+        return AppOpsManager::MODE_IGNORED;
+    }
+    AttributionSourceState attributionSourceState;
+    attributionSourceState.uid = uid;
+    attributionSourceState.packageName = getString(callingPackage);
+    if (attributionTag.has_value()) {
+        attributionSourceState.attributionTag = getString(attributionTag.value());
+    }
 
-    return mode;
+    return service->noteOperationWithState(op, attributionSourceState,
+            shouldCollectNotes(op), message, uid == AID_SYSTEM);
 }
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
@@ -117,13 +136,18 @@
         bool startIfModeDefault, const std::optional<String16>& attributionTag,
         const String16& message) {
     sp<IAppOpsService> service = getService();
-    int32_t mode = service != nullptr
-            ? service->startOperation(getClientId(), op, uid, callingPackage,
-                    attributionTag, startIfModeDefault, shouldCollectNotes(op), message,
-                    uid == AID_SYSTEM)
-            : AppOpsManager::MODE_IGNORED;
+    if (service == nullptr) {
+        return AppOpsManager::MODE_IGNORED;
+    }
+    AttributionSourceState attributionSourceState;
+    attributionSourceState.uid = uid;
+    attributionSourceState.packageName = getString(callingPackage);
+    if (attributionTag.has_value()) {
+        attributionSourceState.attributionTag = getString(attributionTag.value());
+    }
 
-    return mode;
+    return service->startOperationWithState(getClientId(), op, attributionSourceState,
+            startIfModeDefault,shouldCollectNotes(op), message, uid == AID_SYSTEM);
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -133,9 +157,16 @@
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage,
         const std::optional<String16>& attributionTag) {
     sp<IAppOpsService> service = getService();
-    if (service != nullptr) {
-        service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag);
+    if (service == nullptr) {
+        return;
     }
+    AttributionSourceState attributionSourceState;
+    attributionSourceState.uid = uid;
+    attributionSourceState.packageName = getString(callingPackage);
+    if (attributionTag.has_value()) {
+        attributionSourceState.attributionTag = getString(attributionTag.value());
+    }
+    service->finishOperationWithState(getClientId(), op, attributionSourceState);
 }
 
 void AppOpsManager::startWatchingMode(int32_t op, const String16& packageName,
diff --git a/libs/permission/IAppOpsService.cpp b/libs/permission/IAppOpsService.cpp
index 7f235a4..33dd24d 100644
--- a/libs/permission/IAppOpsService.cpp
+++ b/libs/permission/IAppOpsService.cpp
@@ -26,6 +26,8 @@
 
 namespace android {
 
+using android::content::AttributionSourceState;
+
 // ----------------------------------------------------------------------
 
 class BpAppOpsService : public BpInterface<IAppOpsService>
@@ -36,31 +38,30 @@
     {
     }
 
-    virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) {
+    virtual int32_t checkOperationWithState(int32_t code,
+                const AttributionSourceState &attributionSourceState) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeInt32(code);
-        data.writeInt32(uid);
-        data.writeString16(packageName);
-        remote()->transact(CHECK_OPERATION_TRANSACTION, data, &reply);
+        data.writeParcelable(attributionSourceState);
+        remote()->transact(CHECK_OPERATION_WITH_STATE_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
         return reply.readInt32();
     }
 
-    virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
-                const std::optional<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
-                const String16& message, bool shouldCollectMessage) {
+    virtual int32_t noteOperationWithState(int32_t code,
+                const AttributionSourceState& attributionSourceState,
+                bool shouldCollectAsyncNotedOp, const String16& message,
+                bool shouldCollectMessage) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeInt32(code);
-        data.writeInt32(uid);
-        data.writeString16(packageName);
-        data.writeString16(attributionTag);
+        data.writeParcelable(attributionSourceState);
         data.writeBool(shouldCollectAsyncNotedOp);
         data.writeString16(message);
         data.writeBool(shouldCollectMessage);
-        remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply);
+        remote()->transact(NOTE_OPERATION_WITH_STATE_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
         // TODO b/184855056: extract to class
@@ -69,22 +70,20 @@
         return reply.readInt32();
     }
 
-    virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName, const std::optional<String16>& attributionTag,
-                bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message,
+    virtual int32_t startOperationWithState(const sp<IBinder>& token, int32_t code,
+                const AttributionSourceState& attributionSourceState, bool startIfModeDefault,
+                bool shouldCollectAsyncNotedOp, const String16& message,
                 bool shouldCollectMessage) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
-        data.writeInt32(uid);
-        data.writeString16(packageName);
-        data.writeString16(attributionTag);
+        data.writeParcelable(attributionSourceState);
         data.writeBool(startIfModeDefault);
         data.writeBool(shouldCollectAsyncNotedOp);
         data.writeString16(message);
         data.writeBool(shouldCollectMessage);
-        remote()->transact(START_OPERATION_TRANSACTION, data, &reply);
+        remote()->transact(START_OPERATION_WITH_STATE_TRANSACTION, data, &reply);
         // fail on exception
         if (reply.readExceptionCode() != 0) return MODE_ERRORED;
         // TODO b/184855056: extract to class
@@ -93,16 +92,14 @@
         return reply.readInt32();
     }
 
-    virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::optional<String16>& attributionTag) {
+    virtual void finishOperationWithState(const sp<IBinder>& token, int32_t code,
+                const AttributionSourceState& attributionSourceState) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
         data.writeInt32(code);
-        data.writeInt32(uid);
-        data.writeString16(packageName);
-        data.writeString16(attributionTag);
-        remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply);
+        data.writeParcelable(attributionSourceState);
+        remote()->transact(FINISH_OPERATION_WITH_STATE_TRANSACTION, data, &reply);
     }
 
     virtual void startWatchingMode(int32_t op, const String16& packageName,
@@ -189,59 +186,65 @@
 {
     //printf("AppOpsService received: "); data.print();
     switch(code) {
-        case CHECK_OPERATION_TRANSACTION: {
+        case CHECK_OPERATION_WITH_STATE_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsService, data, reply);
             int32_t code = data.readInt32();
-            int32_t uid = data.readInt32();
-            String16 packageName = data.readString16();
-            int32_t res = checkOperation(code, uid, packageName);
+            AttributionSourceState attributionSourceState;
+            status_t status = data.readParcelable(&attributionSourceState);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            int32_t res = checkOperationWithState(code, attributionSourceState);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
-        case NOTE_OPERATION_TRANSACTION: {
+        case NOTE_OPERATION_WITH_STATE_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsService, data, reply);
             int32_t code = data.readInt32();
-            int32_t uid = data.readInt32();
-            String16 packageName = data.readString16();
-            std::optional<String16> attributionTag;
-            data.readString16(&attributionTag);
+            AttributionSourceState attributionSourceState;
+            status_t status = data.readParcelable(&attributionSourceState);
+            if (status != NO_ERROR) {
+                return status;
+            }
             bool shouldCollectAsyncNotedOp = data.readBool();
             String16 message = data.readString16();
             bool shouldCollectMessage = data.readBool();
-            int32_t res = noteOperation(code, uid, packageName, attributionTag,
+            int32_t res = noteOperationWithState(code, attributionSourceState,
                     shouldCollectAsyncNotedOp, message, shouldCollectMessage);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
-        case START_OPERATION_TRANSACTION: {
+        case START_OPERATION_WITH_STATE_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsService, data, reply);
             sp<IBinder> token = data.readStrongBinder();
             int32_t code = data.readInt32();
-            int32_t uid = data.readInt32();
-            String16 packageName = data.readString16();
-            std::optional<String16> attributionTag;
-            data.readString16(&attributionTag);
+            AttributionSourceState attributionSourceState;
+            status_t status = data.readParcelable(&attributionSourceState);
+            if (status != NO_ERROR) {
+                return status;
+            }
             bool startIfModeDefault = data.readBool();
             bool shouldCollectAsyncNotedOp = data.readBool();
             String16 message = data.readString16();
             bool shouldCollectMessage = data.readBool();
-            int32_t res = startOperation(token, code, uid, packageName, attributionTag,
+            int32_t res = startOperationWithState(token, code, attributionSourceState,
                     startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
             reply->writeNoException();
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
-        case FINISH_OPERATION_TRANSACTION: {
+        case FINISH_OPERATION_WITH_STATE_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsService, data, reply);
             sp<IBinder> token = data.readStrongBinder();
             int32_t code = data.readInt32();
-            int32_t uid = data.readInt32();
-            String16 packageName = data.readString16();
-            std::optional<String16> attributionTag;
-            data.readString16(&attributionTag);
-            finishOperation(token, code, uid, packageName, attributionTag);
+            AttributionSourceState attributionSourceState;
+            status_t status = data.readParcelable(&attributionSourceState);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            finishOperationWithState(token, code, attributionSourceState);
             reply->writeNoException();
             return NO_ERROR;
         } break;
diff --git a/libs/permission/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h
index 918fcdb..a5fdc54 100644
--- a/libs/permission/include/binder/IAppOpsService.h
+++ b/libs/permission/include/binder/IAppOpsService.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <android/content/AttributionSourceState.h>
 #include <binder/IAppOpsCallback.h>
 #include <binder/IInterface.h>
 
@@ -27,23 +28,24 @@
 
 namespace android {
 
+using android::content::AttributionSourceState;
+
 // ----------------------------------------------------------------------
 
 class IAppOpsService : public IInterface
 {
 public:
     DECLARE_META_INTERFACE(AppOpsService)
-
-    virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
-    virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
-            const std::optional<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
+    virtual int32_t checkOperationWithState(int32_t code,
+            const AttributionSourceState& attributionSourceState) = 0;
+    virtual int32_t noteOperationWithState(int32_t code,
+            const AttributionSourceState& attributionSourceState, bool shouldCollectAsyncNotedOp,
             const String16& message, bool shouldCollectMessage) = 0;
-    virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::optional<String16>& attributionTag,
-            bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message,
-            bool shouldCollectMessage) = 0;
-    virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::optional<String16>& attributionTag) = 0;
+    virtual int32_t startOperationWithState(const sp<IBinder>& token, int32_t code,
+            const AttributionSourceState& attributionSourceState, bool startIfModeDefault,
+            bool shouldCollectAsyncNotedOp, const String16& message, bool shouldCollectMessage) = 0;
+    virtual void finishOperationWithState(const sp<IBinder>& token, int32_t code,
+            const AttributionSourceState& attributionSourceState) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback) = 0;
     virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
@@ -56,10 +58,10 @@
             int32_t flags, const sp<IAppOpsCallback>& callback) = 0;
 
     enum {
-        CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
-        NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1,
-        START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
-        FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3,
+        CHECK_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+50,
+        NOTE_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+52,
+        START_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+53,
+        FINISH_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+54,
         START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
         STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
         PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 04e2fff..af08a1c 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -66,6 +66,7 @@
 static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl";
 static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
 static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform";
+static const char* ANGLE_SUFFIX_VALUE = "angle";
 
 static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = {
         PERSIST_DRIVER_SUFFIX_PROPERTY,
@@ -80,6 +81,13 @@
         "/vendor/lib/egl";
 #endif
 
+static const char* const SYSTEM_LIB_DIR =
+#if defined(__LP64__)
+        "/system/lib64";
+#else
+        "/system/lib";
+#endif
+
 static void* do_dlopen(const char* path, int mode) {
     ATRACE_CALL();
     return dlopen(path, mode);
@@ -434,98 +442,108 @@
     }
 }
 
+static std::string findLibrary(const std::string libraryName, const std::string searchPath,
+                               const bool exact) {
+    if (exact) {
+        std::string absolutePath = searchPath + "/" + libraryName + ".so";
+        if (!access(absolutePath.c_str(), R_OK)) {
+            return absolutePath;
+        }
+        return std::string();
+    }
+
+    DIR* d = opendir(searchPath.c_str());
+    if (d != nullptr) {
+        struct dirent* e;
+        while ((e = readdir(d)) != nullptr) {
+            if (e->d_type == DT_DIR) {
+                continue;
+            }
+            if (!strcmp(e->d_name, "libGLES_android.so")) {
+                // always skip the software renderer
+                continue;
+            }
+            if (strstr(e->d_name, libraryName.c_str()) == e->d_name) {
+                if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
+                    std::string result = searchPath + "/" + e->d_name;
+                    closedir(d);
+                    return result;
+                }
+            }
+        }
+        closedir(d);
+    }
+    // Driver not found. gah.
+    return std::string();
+}
+
 static void* load_system_driver(const char* kind, const char* suffix, const bool exact) {
     ATRACE_CALL();
-    class MatchFile {
-    public:
-        static std::string find(const char* libraryName, const bool exact) {
-            std::string absolutePath;
-            if (findLibPath(absolutePath, libraryName, exact)) {
-                return absolutePath;
-            }
-
-            // Driver not found. gah.
-            return std::string();
-        }
-    private:
-        static bool findLibPath(std::string& result, const std::string& pattern, bool exact) {
-            const std::string vendorLibEglDirString = std::string(VENDOR_LIB_EGL_DIR);
-            if (exact) {
-                std::string absolutePath = vendorLibEglDirString + "/" + pattern + ".so";
-                if (!access(absolutePath.c_str(), R_OK)) {
-                    result = absolutePath;
-                    return true;
-                }
-                return false;
-            }
-
-            DIR* d = opendir(VENDOR_LIB_EGL_DIR);
-            if (d != nullptr) {
-                struct dirent* e;
-                while ((e = readdir(d)) != nullptr) {
-                    if (e->d_type == DT_DIR) {
-                        continue;
-                    }
-                    if (!strcmp(e->d_name, "libGLES_android.so")) {
-                        // always skip the software renderer
-                        continue;
-                    }
-                    if (strstr(e->d_name, pattern.c_str()) == e->d_name) {
-                        if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
-                            result = vendorLibEglDirString + "/" + e->d_name;
-                            closedir(d);
-                            return true;
-                        }
-                    }
-                }
-                closedir(d);
-            }
-            return false;
-        }
-    };
 
     std::string libraryName = std::string("lib") + kind;
     if (suffix) {
         libraryName += std::string("_") + suffix;
     } else if (!exact) {
-        // Deprecated: we look for files that match
-        //      libGLES_*.so, or:
+        // Deprecated for devices launching in Android 14
+        // Look for files that match
+        //      libGLES_*.so, or,
         //      libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
         libraryName += std::string("_");
     }
-    std::string absolutePath = MatchFile::find(libraryName.c_str(), exact);
+
+    void* dso = nullptr;
+
+    // Only use sphal namespace when system ANGLE binaries are not the default drivers.
+    const bool useSphalNamespace = suffix != nullptr && strcmp(suffix, ANGLE_SUFFIX_VALUE) != 0;
+
+    const std::string absolutePath =
+            findLibrary(libraryName, useSphalNamespace ? VENDOR_LIB_EGL_DIR : SYSTEM_LIB_PATH,
+                        exact);
     if (absolutePath.empty()) {
         // this happens often, we don't want to log an error
         return nullptr;
     }
-    const char* const driver_absolute_path = absolutePath.c_str();
+    const char* const driverAbsolutePath = absolutePath.c_str();
 
-    // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to
-    // the original routine when the namespace does not exist.
-    // See /system/core/rootdir/etc/ld.config.txt for the configuration of the
-    // sphal namespace.
-    void* dso = do_android_load_sphal_library(driver_absolute_path,
-                                              RTLD_NOW | RTLD_LOCAL);
+    // Currently the default driver is unlikely to be ANGLE on most devices,
+    // hence put this first.
+    if (useSphalNamespace) {
+        // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to
+        // the original routine when the namespace does not exist.
+        // See /system/linkerconfig/contents/namespace for the configuration of the
+        // sphal namespace.
+        dso = do_android_load_sphal_library(driverAbsolutePath, RTLD_NOW | RTLD_LOCAL);
+    } else {
+        // Try to load drivers from the default namespace.
+        // See /system/linkerconfig/contents/namespace for the configuration of the
+        // default namespace.
+        dso = do_dlopen(driverAbsolutePath, RTLD_NOW | RTLD_LOCAL);
+    }
+
     if (dso == nullptr) {
         const char* err = dlerror();
-        ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
+        ALOGE("load_driver(%s): %s", driverAbsolutePath, err ? err : "unknown");
         return nullptr;
     }
 
-    ALOGD("loaded %s", driver_absolute_path);
+    ALOGV("loaded %s", driverAbsolutePath);
 
     return dso;
 }
 
 static void* load_angle(const char* kind, android_namespace_t* ns) {
-    const android_dlextinfo dlextinfo = {
-            .flags = ANDROID_DLEXT_USE_NAMESPACE,
-            .library_namespace = ns,
-    };
-
     std::string name = std::string("lib") + kind + "_angle.so";
+    void* so = nullptr;
 
-    void* so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+    if (android::GraphicsEnv::getInstance().shouldUseSystemAngle()) {
+        so = do_dlopen(name.c_str(), RTLD_NOW | RTLD_LOCAL);
+    } else {
+        const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = ns,
+        };
+        so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+    }
 
     if (so) {
         return so;
@@ -563,10 +581,14 @@
     ATRACE_CALL();
 
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
-    if (!ns) {
+    // ANGLE namespace is used for loading ANGLE from apk, and hence if namespace is not
+    // constructed, it means ANGLE apk is not set to be the OpenGL ES driver.
+    // Hence skip if ANGLE apk and system ANGLE are not set to be the OpenGL ES driver.
+    if (!ns && !android::GraphicsEnv::getInstance().shouldUseSystemAngle()) {
         return nullptr;
     }
 
+    // use ANGLE APK driver
     android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE);
     driver_t* hnd = nullptr;
 
@@ -592,6 +614,7 @@
     if (pANGLEGetDisplayPlatform) {
         ALOGV("ANGLE GLES library loaded");
         cnx->angleLoaded = true;
+        android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE);
     } else {
         ALOGV("Native GLES library loaded");
         cnx->angleLoaded = false;
@@ -635,7 +658,13 @@
 Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
                                                         const bool exact) {
     ATRACE_CALL();
-    android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
+    if (suffix && strcmp(suffix, "angle") == 0) {
+        // use system ANGLE driver
+        android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE);
+    } else {
+        android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
+    }
+
     driver_t* hnd = nullptr;
     void* dso = load_system_driver("GLES", suffix, exact);
     if (dso) {
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index ee605c2..a8395d9 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -128,8 +128,8 @@
             return false;
         }
     } else {
-        // If we are here, ANGLE is loaded as built-in gl driver in the sphal.
-        so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags);
+        // If we are here, ANGLE is loaded as the default OpenGL ES driver.
+        so = dlopen(kAngleEs2Lib, kAngleDlFlags);
         if (so) {
             ALOGD("dlopen (%s) success at %p", kAngleEs2Lib, so);
         } else {
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index f06a045..11b636d 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -163,11 +163,13 @@
         addLoadingTime(driver, driverLoadingTime, &appInfo);
         appInfo.appPackageName = appPackageName;
         appInfo.driverVersionCode = driverVersionCode;
-        appInfo.angleInUse = driverPackageName == "angle";
+        appInfo.angleInUse =
+                driver == GpuStatsInfo::Driver::ANGLE || driverPackageName == "angle";
         appInfo.lastAccessTime = std::chrono::system_clock::now();
         mAppStats.insert({appStatsKey, appInfo});
     } else {
-        mAppStats[appStatsKey].angleInUse = driverPackageName == "angle";
+        mAppStats[appStatsKey].angleInUse =
+                driver == GpuStatsInfo::Driver::ANGLE || driverPackageName == "angle";
         addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
         mAppStats[appStatsKey].lastAccessTime = std::chrono::system_clock::now();
     }
diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.cpp b/services/inputflinger/PreferStylusOverTouchBlocker.cpp
index ee0ab33..d9d0450 100644
--- a/services/inputflinger/PreferStylusOverTouchBlocker.cpp
+++ b/services/inputflinger/PreferStylusOverTouchBlocker.cpp
@@ -15,10 +15,15 @@
  */
 
 #include "PreferStylusOverTouchBlocker.h"
+#include <com_android_input_flags.h>
 #include <input/PrintTools.h>
 
+namespace input_flags = com::android::input::flags;
+
 namespace android {
 
+const bool BLOCK_TOUCH_WHEN_STYLUS_HOVER = !input_flags::disable_reject_touch_on_stylus_hover();
+
 static std::pair<bool, bool> checkToolType(const NotifyMotionArgs& args) {
     bool hasStylus = false;
     bool hasTouch = false;
@@ -96,8 +101,11 @@
 std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion(
         const NotifyMotionArgs& args) {
     const auto [hasTouch, hasStylus] = checkToolType(args);
-    const bool isUpOrCancel =
-            args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL;
+    const bool isDisengageOrCancel = BLOCK_TOUCH_WHEN_STYLUS_HOVER
+            ? (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT ||
+               args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL)
+            : (args.action == AMOTION_EVENT_ACTION_UP ||
+               args.action == AMOTION_EVENT_ACTION_CANCEL);
 
     if (hasTouch && hasStylus) {
         mDevicesWithMixedToolType.insert(args.deviceId);
@@ -109,7 +117,7 @@
         if (mCanceledDevices.find(args.deviceId) != mCanceledDevices.end()) {
             // If we started to cancel events from this device, continue to do so to keep
             // the stream consistent. It should happen at most once per "mixed" device.
-            if (isUpOrCancel) {
+            if (isDisengageOrCancel) {
                 mCanceledDevices.erase(args.deviceId);
                 mLastTouchEvents.erase(args.deviceId);
             }
@@ -119,10 +127,13 @@
     }
 
     const bool isStylusEvent = hasStylus;
-    const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN;
+    const bool isEngage = BLOCK_TOUCH_WHEN_STYLUS_HOVER
+            ? (args.action == AMOTION_EVENT_ACTION_DOWN ||
+               args.action == AMOTION_EVENT_ACTION_HOVER_ENTER)
+            : (args.action == AMOTION_EVENT_ACTION_DOWN);
 
     if (isStylusEvent) {
-        if (isDown) {
+        if (isEngage) {
             // Reject all touch while stylus is down
             mActiveStyli.insert(args.deviceId);
 
@@ -143,7 +154,7 @@
             result.push_back(args);
             return result;
         }
-        if (isUpOrCancel) {
+        if (isDisengageOrCancel) {
             mActiveStyli.erase(args.deviceId);
         }
         // Never drop stylus events
@@ -158,7 +169,7 @@
         }
 
         const bool shouldDrop = mCanceledDevices.find(args.deviceId) != mCanceledDevices.end();
-        if (isUpOrCancel) {
+        if (isDisengageOrCancel) {
             mCanceledDevices.erase(args.deviceId);
             mLastTouchEvents.erase(args.deviceId);
         }
@@ -169,7 +180,7 @@
             return {};
         }
 
-        if (!isUpOrCancel) {
+        if (!isDisengageOrCancel) {
             mLastTouchEvents[args.deviceId] = args;
         }
         return {args};
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index c7d98ab..c889b9b 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -69,6 +69,16 @@
         android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "Injection");
 
 /**
+ * Generally, we always log whenever events are dropped. However, to reduce logspam, some messages
+ * are suppressed.
+ * Log additional debug messages about dropped input events with this flag.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherDroppedEventsVerbose DEBUG".
+ * Requires system_server restart via `adb shell stop && adb shell start`.
+ */
+const bool DEBUG_DROPPED_EVENTS_VERBOSE =
+        android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "DroppedEventsVerbose");
+
+/**
  * Log debug messages about input focus tracking.
  * Enable this via "adb shell setprop log.tag.InputDispatcherFocus DEBUG" (requires restart)
  */
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 53e0855..156697a 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -72,6 +72,8 @@
 using android::os::InputEventInjectionSync;
 namespace input_flags = com::android::input::flags;
 
+static const bool REMOVE_APP_SWITCH_DROPS = input_flags::remove_app_switch_drops();
+
 namespace android::inputdispatcher {
 
 namespace {
@@ -756,10 +758,6 @@
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy)
-      : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {}
-
-InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
-                                 std::chrono::nanoseconds staleEventTimeout)
       : mPolicy(policy),
         mPendingEvent(nullptr),
         mLastDropReason(DropReason::NOT_DROPPED),
@@ -774,7 +772,6 @@
         mMaximumObscuringOpacityForTouch(1.0f),
         mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
         mWindowTokenWithPointerCapture(nullptr),
-        mStaleEventTimeout(staleEventTimeout),
         mLatencyAggregator(),
         mLatencyTracker(&mLatencyAggregator) {
     mLooper = sp<Looper>::make(false);
@@ -956,20 +953,25 @@
     // Optimize latency of app switches.
     // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
     // been pressed.  When it expires, we preempt dispatch and drop all other pending events.
-    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
-    if (mAppSwitchDueTime < *nextWakeupTime) {
-        *nextWakeupTime = mAppSwitchDueTime;
+    bool isAppSwitchDue;
+    if (!REMOVE_APP_SWITCH_DROPS) {
+        isAppSwitchDue = mAppSwitchDueTime <= currentTime;
+        if (mAppSwitchDueTime < *nextWakeupTime) {
+            *nextWakeupTime = mAppSwitchDueTime;
+        }
     }
 
     // Ready to start a new event.
     // If we don't already have a pending event, go grab one.
     if (!mPendingEvent) {
         if (mInboundQueue.empty()) {
-            if (isAppSwitchDue) {
-                // The inbound queue is empty so the app switch key we were waiting
-                // for will never arrive.  Stop waiting for it.
-                resetPendingAppSwitchLocked(false);
-                isAppSwitchDue = false;
+            if (!REMOVE_APP_SWITCH_DROPS) {
+                if (isAppSwitchDue) {
+                    // The inbound queue is empty so the app switch key we were waiting
+                    // for will never arrive.  Stop waiting for it.
+                    resetPendingAppSwitchLocked(false);
+                    isAppSwitchDue = false;
+                }
             }
 
             // Synthesize a key repeat if appropriate.
@@ -1067,12 +1069,14 @@
 
         case EventEntry::Type::KEY: {
             std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
-            if (isAppSwitchDue) {
-                if (isAppSwitchKeyEvent(*keyEntry)) {
-                    resetPendingAppSwitchLocked(true);
-                    isAppSwitchDue = false;
-                } else if (dropReason == DropReason::NOT_DROPPED) {
-                    dropReason = DropReason::APP_SWITCH;
+            if (!REMOVE_APP_SWITCH_DROPS) {
+                if (isAppSwitchDue) {
+                    if (isAppSwitchKeyEvent(*keyEntry)) {
+                        resetPendingAppSwitchLocked(true);
+                        isAppSwitchDue = false;
+                    } else if (dropReason == DropReason::NOT_DROPPED) {
+                        dropReason = DropReason::APP_SWITCH;
+                    }
                 }
             }
             if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
@@ -1088,8 +1092,10 @@
         case EventEntry::Type::MOTION: {
             std::shared_ptr<MotionEntry> motionEntry =
                     std::static_pointer_cast<MotionEntry>(mPendingEvent);
-            if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
-                dropReason = DropReason::APP_SWITCH;
+            if (!REMOVE_APP_SWITCH_DROPS) {
+                if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
+                    dropReason = DropReason::APP_SWITCH;
+                }
             }
             if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
                 dropReason = DropReason::STALE;
@@ -1104,8 +1110,10 @@
         case EventEntry::Type::SENSOR: {
             std::shared_ptr<SensorEntry> sensorEntry =
                     std::static_pointer_cast<SensorEntry>(mPendingEvent);
-            if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
-                dropReason = DropReason::APP_SWITCH;
+            if (!REMOVE_APP_SWITCH_DROPS) {
+                if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
+                    dropReason = DropReason::APP_SWITCH;
+                }
             }
             //  Sensor timestamps use SYSTEM_TIME_BOOTTIME time base, so we can't use
             // 'currentTime' here, get SYSTEM_TIME_BOOTTIME instead.
@@ -1131,7 +1139,7 @@
 }
 
 bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
-    return std::chrono::nanoseconds(currentTime - entry.eventTime) >= mStaleEventTimeout;
+    return mPolicy.isStaleEvent(currentTime, entry.eventTime);
 }
 
 /**
@@ -1207,21 +1215,23 @@
             // If the application takes too long to catch up then we drop all events preceding
             // the app switch key.
             const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
-            if (isAppSwitchKeyEvent(keyEntry)) {
-                if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
-                    mAppSwitchSawKeyDown = true;
-                } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
-                    if (mAppSwitchSawKeyDown) {
-                        if (DEBUG_APP_SWITCH) {
-                            ALOGD("App switch is pending!");
+
+            if (!REMOVE_APP_SWITCH_DROPS) {
+                if (isAppSwitchKeyEvent(keyEntry)) {
+                    if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
+                        mAppSwitchSawKeyDown = true;
+                    } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
+                        if (mAppSwitchSawKeyDown) {
+                            if (DEBUG_APP_SWITCH) {
+                                ALOGD("App switch is pending!");
+                            }
+                            mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
+                            mAppSwitchSawKeyDown = false;
+                            needWake = true;
                         }
-                        mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
-                        mAppSwitchSawKeyDown = false;
-                        needWake = true;
                     }
                 }
             }
-
             // If a new up event comes in, and the pending event with same key code has been asked
             // to try again later because of the policy. We have to reset the intercept key wake up
             // time for it may have been handled in the policy and could be dropped.
@@ -2032,10 +2042,10 @@
         if (connection != nullptr) {
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
         } else {
-            if (DEBUG_FOCUS) {
-                ALOGD("Dropping event delivery to target with channel '%s' because it "
-                      "is no longer registered with the input dispatcher.",
-                      inputTarget.inputChannel->getName().c_str());
+            if (DEBUG_DROPPED_EVENTS_VERBOSE) {
+                LOG(INFO) << "Dropping event delivery to target with channel "
+                          << inputTarget.inputChannel->getName()
+                          << " because it is no longer registered with the input dispatcher.";
             }
         }
     }
@@ -2453,10 +2463,11 @@
         // If the pointer is not currently down, then ignore the event.
         if (!tempTouchState.isDown(entry.deviceId) &&
             maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
-            LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId
-                      << " is not down or we previously "
-                         "dropped the pointer down event in display "
-                      << displayId << ": " << entry.getDescription();
+            if (DEBUG_DROPPED_EVENTS_VERBOSE) {
+                LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId
+                          << " is not down or we previously dropped the pointer down event in "
+                          << "display " << displayId << ": " << entry.getDescription();
+            }
             outInjectionResult = InputEventInjectionResult::FAILED;
             return {};
         }
@@ -2864,8 +2875,13 @@
         it = inputTargets.end() - 1;
     }
 
-    LOG_ALWAYS_FATAL_IF(it->flags != targetFlags);
-    LOG_ALWAYS_FATAL_IF(it->globalScaleFactor != windowInfo->globalScaleFactor);
+    if (it->flags != targetFlags) {
+        LOG(ERROR) << "Flags don't match! targetFlags=" << targetFlags.string() << ", it=" << *it;
+    }
+    if (it->globalScaleFactor != windowInfo->globalScaleFactor) {
+        LOG(ERROR) << "Mismatch! it->globalScaleFactor=" << it->globalScaleFactor
+                   << ", windowInfo->globalScaleFactor=" << windowInfo->globalScaleFactor;
+    }
 }
 
 void InputDispatcher::addPointerWindowTargetLocked(
@@ -2911,10 +2927,12 @@
     }
 
     if (it->flags != targetFlags) {
-        logDispatchStateLocked();
-        LOG(FATAL) << "Flags don't match! targetFlags=" << targetFlags.string() << ", it=" << *it;
+        LOG(ERROR) << "Flags don't match! targetFlags=" << targetFlags.string() << ", it=" << *it;
     }
-    LOG_ALWAYS_FATAL_IF(it->globalScaleFactor != windowInfo->globalScaleFactor);
+    if (it->globalScaleFactor != windowInfo->globalScaleFactor) {
+        LOG(ERROR) << "Mismatch! it->globalScaleFactor=" << it->globalScaleFactor
+                   << ", windowInfo->globalScaleFactor=" << windowInfo->globalScaleFactor;
+    }
 
     it->addPointers(pointerIds, windowInfo->transform);
 }
@@ -4422,7 +4440,8 @@
             const auto touchStateIt = mTouchStatesByDisplay.find(args.displayId);
             if (touchStateIt != mTouchStatesByDisplay.end()) {
                 const TouchState& touchState = touchStateIt->second;
-                if (touchState.hasTouchingPointers(args.deviceId)) {
+                if (touchState.hasTouchingPointers(args.deviceId) ||
+                    touchState.hasHoveringPointers(args.deviceId)) {
                     policyFlags |= POLICY_FLAG_PASS_TO_USER;
                 }
             }
@@ -4534,6 +4553,7 @@
 }
 
 void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
+    // TODO(b/308677868) Remove device reset from the InputListener interface
     if (debugInboundEventDetails()) {
         ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args.eventTime,
               args.deviceId);
@@ -4675,6 +4695,30 @@
             }
 
             mLock.lock();
+
+            if (policyFlags & POLICY_FLAG_FILTERED) {
+                // The events from InputFilter impersonate real hardware devices. Check these
+                // events for consistency and print an error. An inconsistent event sent from
+                // InputFilter could cause a crash in the later stages of dispatching pipeline.
+                auto [it, _] =
+                        mInputFilterVerifiersByDisplay
+                                .try_emplace(displayId,
+                                             StringPrintf("Injection on %" PRId32, displayId));
+                InputVerifier& verifier = it->second;
+
+                Result<void> result =
+                        verifier.processMovement(resolvedDeviceId, motionEvent.getSource(),
+                                                 motionEvent.getAction(),
+                                                 motionEvent.getPointerCount(),
+                                                 motionEvent.getPointerProperties(),
+                                                 motionEvent.getSamplePointerCoords(), flags);
+                if (!result.ok()) {
+                    logDispatchStateLocked();
+                    LOG(ERROR) << "Inconsistent event: " << motionEvent
+                               << ", reason: " << result.error();
+                }
+            }
+
             const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes();
             const size_t pointerCount = motionEvent.getPointerCount();
             const std::vector<PointerProperties>
@@ -5800,6 +5844,9 @@
         dump += INDENT "Connections: <none>\n";
     }
 
+    dump += "input_flags::remove_app_switch_drops() = ";
+    dump += toString(REMOVE_APP_SWITCH_DROPS);
+    dump += "\n";
     if (isAppSwitchPendingLocked()) {
         dump += StringPrintf(INDENT "AppSwitch: pending, due in %" PRId64 "ms\n",
                              ns2ms(mAppSwitchDueTime - now()));
@@ -6736,6 +6783,7 @@
         // Remove the associated touch mode state.
         mTouchModePerDisplay.erase(displayId);
         mVerifiersByDisplay.erase(displayId);
+        mInputFilterVerifiersByDisplay.erase(displayId);
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index a1127a0..e428c4e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -82,8 +82,6 @@
     static constexpr bool kDefaultInTouchMode = true;
 
     explicit InputDispatcher(InputDispatcherPolicyInterface& policy);
-    explicit InputDispatcher(InputDispatcherPolicyInterface& policy,
-                             std::chrono::nanoseconds staleEventTimeout);
     ~InputDispatcher() override;
 
     void dump(std::string& dump) const override;
@@ -288,7 +286,8 @@
     void transformMotionEntryForInjectionLocked(MotionEntry&,
                                                 const ui::Transform& injectedTransform) const
             REQUIRES(mLock);
-
+    // Per-display correction of injected events
+    std::map</*displayId*/ int32_t, InputVerifier> mInputFilterVerifiersByDisplay GUARDED_BY(mLock);
     std::condition_variable mInjectionSyncFinished;
     void incrementPendingForegroundDispatches(EventEntry& entry);
     void decrementPendingForegroundDispatches(EventEntry& entry);
@@ -461,9 +460,6 @@
      */
     std::optional<nsecs_t> mNoFocusedWindowTimeoutTime GUARDED_BY(mLock);
 
-    // Amount of time to allow for an event to be dispatched (measured since its eventTime)
-    // before considering it stale and dropping it.
-    const std::chrono::nanoseconds mStaleEventTimeout;
     bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry);
 
     bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index af28e48..bf48804 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -18,6 +18,7 @@
 
 #include "InputDispatcherConfiguration.h"
 
+#include <android-base/properties.h>
 #include <binder/IBinder.h>
 #include <gui/InputApplication.h>
 #include <input/Input.h>
@@ -118,6 +119,16 @@
     /* Poke user activity for an event dispatched to a window. */
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
 
+    /*
+     * Return true if the provided event is stale, and false otherwise. Used for determining
+     * whether the dispatcher should drop the event.
+     */
+    virtual bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) {
+        static const std::chrono::duration STALE_EVENT_TIMEOUT =
+                std::chrono::seconds(10) * android::base::HwTimeoutMultiplier();
+        return std::chrono::nanoseconds(currentTime - eventTime) >= STALE_EVENT_TIMEOUT;
+    }
+
     /* Notifies the policy that a pointer down event has occurred outside the current focused
      * window.
      *
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 5766b14..0582649 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -1046,6 +1046,14 @@
     return mReader->mPreventingTouchpadTaps;
 }
 
+void InputReader::ContextImpl::setLastKeyDownTimestamp(nsecs_t when) {
+    mReader->mLastKeyDownTimestamp = when;
+}
+
+nsecs_t InputReader::ContextImpl::getLastKeyDownTimestamp() {
+    return mReader->mLastKeyDownTimestamp;
+}
+
 void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) {
     // lock is already held by the input loop
     mReader->disableVirtualKeysUntilLocked(time);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 9a297c9..4c78db3 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -158,6 +158,9 @@
         void setPreventingTouchpadTaps(bool prevent) REQUIRES(mReader->mLock)
                 REQUIRES(mLock) override;
         bool isPreventingTouchpadTaps() REQUIRES(mReader->mLock) REQUIRES(mLock) override;
+        void setLastKeyDownTimestamp(nsecs_t when) REQUIRES(mReader->mLock)
+                REQUIRES(mLock) override;
+        nsecs_t getLastKeyDownTimestamp() REQUIRES(mReader->mLock) REQUIRES(mLock) override;
     } mContext;
 
     friend class ContextImpl;
@@ -198,6 +201,9 @@
     // true if tap-to-click on touchpad currently disabled
     bool mPreventingTouchpadTaps GUARDED_BY(mLock){false};
 
+    // records timestamp of the last key press on the physical keyboard
+    nsecs_t mLastKeyDownTimestamp GUARDED_BY(mLock){0};
+
     // low-level input event decoding and device management
     [[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count)
             REQUIRES(mLock);
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index aed7563..69b2315 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -65,6 +65,9 @@
 
     virtual void setPreventingTouchpadTaps(bool prevent) = 0;
     virtual bool isPreventingTouchpadTaps() = 0;
+
+    virtual void setLastKeyDownTimestamp(nsecs_t when) = 0;
+    virtual nsecs_t getLastKeyDownTimestamp() = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 531fc67..f068cc8 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -270,7 +270,7 @@
             keyDown.flags = flags;
             mKeyDowns.push_back(keyDown);
         }
-        onKeyDownProcessed();
+        onKeyDownProcessed(downTime);
     } else {
         // Remove key down.
         if (keyDownIndex) {
@@ -448,8 +448,9 @@
     return out;
 }
 
-void KeyboardInputMapper::onKeyDownProcessed() {
+void KeyboardInputMapper::onKeyDownProcessed(nsecs_t downTime) {
     InputReaderContext& context = *getContext();
+    context.setLastKeyDownTimestamp(downTime);
     if (context.isPreventingTouchpadTaps()) {
         // avoid pinging java service unnecessarily, just fade pointer again if it became visible
         context.fadePointer();
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 09808df..500256b 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -107,7 +107,7 @@
     void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset);
     std::optional<DisplayViewport> findViewport(const InputReaderConfiguration& readerConfig);
     [[nodiscard]] std::list<NotifyArgs> cancelAllDownKeys(nsecs_t when);
-    void onKeyDownProcessed();
+    void onKeyDownProcessed(nsecs_t downTime);
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
index f70be72..b0fc903 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
@@ -152,6 +152,14 @@
     }
 }
 
+size_t MultiTouchMotionAccumulator::getActiveSlotsCount() const {
+    if (!mUsingSlotsProtocol) {
+        return mCurrentSlot < 0 ? 0 : mCurrentSlot;
+    }
+    return std::count_if(mSlots.begin(), mSlots.end(),
+                         [](const Slot& slot) { return slot.mInUse; });
+}
+
 // --- MultiTouchMotionAccumulator::Slot ---
 
 ToolType MultiTouchMotionAccumulator::Slot::getToolType() const {
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
index 943dde5..0e3e2bb 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h
@@ -77,6 +77,7 @@
     void process(const RawEvent* rawEvent);
     void finishSync();
 
+    size_t getActiveSlotsCount() const;
     inline size_t getSlotCount() const { return mSlots.size(); }
     inline const Slot& getSlot(size_t index) const {
         LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index);
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 64e8825..db31ded 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -58,6 +58,7 @@
         "InputReader_test.cpp",
         "InstrumentedInputReader.cpp",
         "LatencyTracker_test.cpp",
+        "MultiTouchMotionAccumulator_test.cpp",
         "NotifyArgs_test.cpp",
         "PointerChoreographer_test.cpp",
         "PreferStylusOverTouch_test.cpp",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 3c87f71..2509c60 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -112,8 +112,6 @@
 // An arbitrary pid of the gesture monitor window
 static constexpr gui::Pid MONITOR_PID{2001};
 
-static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
-
 /**
  * If we expect to receive the event, the timeout can be made very long. When the test are running
  * correctly, we will actually never wait until the end of the timeout because the wait will end
@@ -348,6 +346,8 @@
         mInterceptKeyTimeout = timeout;
     }
 
+    void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; }
+
     void assertUserActivityPoked() {
         std::scoped_lock lock(mLock);
         ASSERT_TRUE(mPokedUserActivity) << "Expected user activity to have been poked";
@@ -391,6 +391,8 @@
 
     std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
 
+    std::chrono::nanoseconds mStaleEventTimeout = 1000ms;
+
     BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;
 
     // All three ANR-related callbacks behave the same way, so we use this generic function to wait
@@ -545,6 +547,10 @@
         mPokedUserActivity = true;
     }
 
+    bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) override {
+        return std::chrono::nanoseconds(currentTime - eventTime) >= mStaleEventTimeout;
+    }
+
     void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
         std::scoped_lock lock(mLock);
         mOnPointerDownToken = newToken;
@@ -586,7 +592,8 @@
 
     void SetUp() override {
         mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>();
-        mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, STALE_EVENT_TIMEOUT);
+        mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy);
+
         mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
         // Start InputDispatcher thread
         ASSERT_EQ(OK, mDispatcher->start());
@@ -2160,6 +2167,69 @@
 }
 
 /**
+ * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers.
+ * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not
+ * interactive, it might stop sending this flag.
+ * We've already ensured the consistency of the touch event in this case, and we should also ensure
+ * the consistency of the hover event in this case.
+ *
+ * Test procedure:
+ * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT
+ * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT
+ *
+ * We expect to receive two full streams of hover events.
+ */
+TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+    sp<FakeWindowHandle> window =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+    window->setFrame(Rect(0, 0, 300, 300));
+
+    mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
+
+    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+                                      .policyFlags(DEFAULT_POLICY_FLAGS)
+                                      .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101))
+                                      .build());
+    window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
+                                      .policyFlags(DEFAULT_POLICY_FLAGS)
+                                      .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
+                                      .build());
+    window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
+
+    // Send hover exit without the default policy flags.
+    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
+                                      .policyFlags(0)
+                                      .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102))
+                                      .build());
+
+    window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+
+    // Send a simple hover event stream, ensure dispatcher not crashed and window can receive
+    // right event.
+    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+                                      .policyFlags(DEFAULT_POLICY_FLAGS)
+                                      .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201))
+                                      .build());
+    window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
+                                      .policyFlags(DEFAULT_POLICY_FLAGS)
+                                      .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
+                                      .build());
+    window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
+
+    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
+                                      .policyFlags(DEFAULT_POLICY_FLAGS)
+                                      .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202))
+                                      .build());
+    window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+}
+
+/**
  * Two windows: a window on the left and a window on the right.
  * Mouse is hovered from the right window into the left window.
  * Next, we tap on the left window, where the cursor was last seen.
@@ -7529,6 +7599,8 @@
     mWindow->consumeFocusEvent(false);
 
     KeyEvent event;
+    static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
+    mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT);
     const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) -
             std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count();
 
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index dac4ea0..787444c 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -80,9 +80,15 @@
 }
 
 std::list<NotifyArgs> InputMapperUnitTest::process(int32_t type, int32_t code, int32_t value) {
+    nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+    return process(when, type, code, value);
+}
+
+std::list<NotifyArgs> InputMapperUnitTest::process(nsecs_t when, int32_t type, int32_t code,
+                                                   int32_t value) {
     RawEvent event;
-    event.when = systemTime(SYSTEM_TIME_MONOTONIC);
-    event.readTime = event.when;
+    event.when = when;
+    event.readTime = when;
     event.deviceId = mMapper->getDeviceContext().getEventHubId();
     event.type = type;
     event.code = code;
diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h
index c2ac258..3f9061f 100644
--- a/services/inputflinger/tests/InputMapperTest.h
+++ b/services/inputflinger/tests/InputMapperTest.h
@@ -52,6 +52,7 @@
     void setKeyCodeState(KeyState state, std::set<int> keyCodes);
 
     std::list<NotifyArgs> process(int32_t type, int32_t code, int32_t value);
+    std::list<NotifyArgs> process(nsecs_t when, int32_t type, int32_t code, int32_t value);
 
     MockEventHubInterface mMockEventHub;
     std::shared_ptr<FakePointerController> mFakePointerController;
diff --git a/services/inputflinger/tests/InstrumentedInputReader.h b/services/inputflinger/tests/InstrumentedInputReader.h
index ca85558..e9c7bb4 100644
--- a/services/inputflinger/tests/InstrumentedInputReader.h
+++ b/services/inputflinger/tests/InstrumentedInputReader.h
@@ -106,6 +106,9 @@
         void setPreventingTouchpadTaps(bool prevent) override { mPreventingTouchpadTaps = prevent; }
         bool isPreventingTouchpadTaps() override { return mPreventingTouchpadTaps; }
 
+        void setLastKeyDownTimestamp(nsecs_t when) override { mLastKeyDownTimestamp = when; };
+        nsecs_t getLastKeyDownTimestamp() override { return mLastKeyDownTimestamp; };
+
     private:
         int32_t mGlobalMetaState;
         bool mUpdateGlobalMetaStateWasCalled;
@@ -113,6 +116,7 @@
         std::optional<nsecs_t> mRequestedTimeout;
         std::vector<InputDeviceInfo> mExternalStylusDevices;
         bool mPreventingTouchpadTaps{false};
+        nsecs_t mLastKeyDownTimestamp;
     } mFakeContext;
 
     friend class InputReaderTest;
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 05823cd..7394913 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -77,6 +77,9 @@
     MOCK_METHOD(void, setPreventingTouchpadTaps, (bool prevent), (override));
     MOCK_METHOD(bool, isPreventingTouchpadTaps, (), (override));
 
+    MOCK_METHOD(void, setLastKeyDownTimestamp, (nsecs_t when));
+    MOCK_METHOD(nsecs_t, getLastKeyDownTimestamp, ());
+
 private:
     int32_t mGeneration = 0;
 };
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 48f5673..2ef7999 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -26,6 +26,7 @@
 namespace android {
 
 using testing::_;
+using testing::Args;
 using testing::DoAll;
 using testing::Return;
 using testing::SetArgPointee;
@@ -158,4 +159,18 @@
     testTouchpadTapStateForKeys(metaKeys, /* expectPrevent= */ false);
 }
 
+TEST_F(KeyboardInputMapperUnitTest, KeyPressTimestampRecorded) {
+    nsecs_t when = ARBITRARY_TIME;
+    std::vector<int32_t> keyCodes{KEY_0, KEY_A, KEY_LEFTCTRL, KEY_RIGHTALT, KEY_LEFTSHIFT};
+    EXPECT_CALL(mMockInputReaderContext, setLastKeyDownTimestamp)
+            .With(Args<0>(when))
+            .Times(keyCodes.size());
+    for (int32_t keyCode : keyCodes) {
+        process(when, EV_KEY, keyCode, 1);
+        process(when, EV_SYN, SYN_REPORT, 0);
+        process(when, EV_KEY, keyCode, 0);
+        process(when, EV_SYN, SYN_REPORT, 0);
+    }
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp b/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
new file mode 100644
index 0000000..9fa6cdd
--- /dev/null
+++ b/services/inputflinger/tests/MultiTouchMotionAccumulator_test.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MultiTouchMotionAccumulator.h"
+#include "InputMapperTest.h"
+
+namespace android {
+
+class MultiTouchMotionAccumulatorTest : public InputMapperUnitTest {
+protected:
+    static constexpr size_t SLOT_COUNT = 8;
+
+    MultiTouchMotionAccumulator mMotionAccumulator;
+
+    void processMotionEvent(int32_t type, int32_t code, int32_t value) {
+        RawEvent event;
+        event.when = ARBITRARY_TIME;
+        event.readTime = READ_TIME;
+        event.deviceId = EVENTHUB_ID;
+        event.type = type;
+        event.code = code;
+        event.value = value;
+        mMotionAccumulator.process(&event);
+    }
+};
+
+TEST_F(MultiTouchMotionAccumulatorTest, ActiveSlotCountUsingSlotsProtocol) {
+    mMotionAccumulator.configure(*mDeviceContext, SLOT_COUNT, /*usingSlotsProtocol=*/true);
+    // We expect active slot count to match the touches being tracked
+    // first touch
+    processMotionEvent(EV_ABS, ABS_MT_SLOT, 0);
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, 123);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(1u, mMotionAccumulator.getActiveSlotsCount());
+
+    // second touch
+    processMotionEvent(EV_ABS, ABS_MT_SLOT, 1);
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, 456);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(2u, mMotionAccumulator.getActiveSlotsCount());
+
+    // second lifted
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(1u, mMotionAccumulator.getActiveSlotsCount());
+
+    // first lifted
+    processMotionEvent(EV_ABS, ABS_MT_SLOT, 0);
+    processMotionEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+    processMotionEvent(EV_SYN, SYN_REPORT, 0);
+    ASSERT_EQ(0u, mMotionAccumulator.getActiveSlotsCount());
+}
+
+TEST_F(MultiTouchMotionAccumulatorTest, ActiveSlotCountNotUsingSlotsProtocol) {
+    mMotionAccumulator.configure(*mDeviceContext, SLOT_COUNT, /*usingSlotsProtocol=*/false);
+
+    // first touch
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_X, 0);
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
+    processMotionEvent(EV_SYN, SYN_MT_REPORT, 0);
+    ASSERT_EQ(1u, mMotionAccumulator.getActiveSlotsCount());
+
+    // second touch
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_X, 50);
+    processMotionEvent(EV_ABS, ABS_MT_POSITION_Y, 50);
+    processMotionEvent(EV_SYN, SYN_MT_REPORT, 0);
+    ASSERT_EQ(2u, mMotionAccumulator.getActiveSlotsCount());
+
+    // reset
+    mMotionAccumulator.finishSync();
+    ASSERT_EQ(0u, mMotionAccumulator.getActiveSlotsCount());
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index bdedfdf..e1c0fe2 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -360,6 +360,12 @@
 
     void setPreventingTouchpadTaps(bool prevent) {}
     bool isPreventingTouchpadTaps() { return mFdp->ConsumeBool(); };
+
+    void setLastKeyDownTimestamp(nsecs_t when) { mLastKeyDownTimestamp = when; };
+    nsecs_t getLastKeyDownTimestamp() { return mLastKeyDownTimestamp; };
+
+private:
+    nsecs_t mLastKeyDownTimestamp;
 };
 
 template <class Fdp>
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index a8f05bb..1f8a3f5 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -102,6 +102,9 @@
     DUMP_FLAG(misc1);
     DUMP_FLAG(late_boot_misc2);
     DUMP_FLAG(vrr_config);
+    DUMP_FLAG(hotplug2);
+    DUMP_FLAG(hdcp_level_hal);
+    DUMP_FLAG(multithreaded_present);
 
 #undef DUMP_FLAG
 }
@@ -165,6 +168,9 @@
 FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "")
 FLAG_MANAGER_READ_ONLY_FLAG(misc1, "")
 FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config")
+FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "")
+FLAG_MANAGER_READ_ONLY_FLAG(hdcp_level_hal, "")
+FLAG_MANAGER_READ_ONLY_FLAG(multithreaded_present, "debug.sf.multithreaded_present")
 
 /// Trunk stable server flags ///
 FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "")
diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h
index 5a353bb..10784a7 100644
--- a/services/surfaceflinger/FlagManager.h
+++ b/services/surfaceflinger/FlagManager.h
@@ -51,6 +51,9 @@
     bool enable_small_area_detection() const;
     bool misc1() const;
     bool vrr_config() const;
+    bool hotplug2() const;
+    bool hdcp_level_hal() const;
+    bool multithreaded_present() const;
 
     /// Trunk stable server flags ///
     bool late_boot_misc2() const;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 7a85da0..38974a2 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -332,6 +332,14 @@
     return geomBufferSize.toFloatRect();
 }
 
+bool LayerSnapshot::isFrontBuffered() const {
+    if (!externalTexture) {
+        return false;
+    }
+
+    return externalTexture->getUsage() & AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
+}
+
 Hwc2::IComposerClient::BlendMode LayerSnapshot::getBlendMode(
         const RequestedLayerState& requested) const {
     auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 4fd6495..73ee22f 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -143,6 +143,7 @@
     std::string getIsVisibleReason() const;
     bool hasInputInfo() const;
     FloatRect sourceBounds() const;
+    bool isFrontBuffered() const;
     Hwc2::IComposerClient::BlendMode getBlendMode(const RequestedLayerState& requested) const;
     friend std::ostream& operator<<(std::ostream& os, const LayerSnapshot& obj);
     void merge(const RequestedLayerState& requested, bool forceUpdate, bool displayChanges,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 700baa2..66ea15c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -4024,10 +4024,10 @@
     return getAlpha() > 0.0f || hasBlur();
 }
 
-void Layer::onPostComposition(const DisplayDevice* display,
-                              const std::shared_ptr<FenceTime>& glDoneFence,
-                              const std::shared_ptr<FenceTime>& presentFence,
-                              const CompositorTiming& compositorTiming) {
+void Layer::onCompositionPresented(const DisplayDevice* display,
+                                   const std::shared_ptr<FenceTime>& glDoneFence,
+                                   const std::shared_ptr<FenceTime>& presentFence,
+                                   const CompositorTiming& compositorTiming) {
     // mFrameLatencyNeeded is true when a new frame was latched for the
     // composition.
     if (!mBufferInfo.mFrameLatencyNeeded) return;
@@ -4230,6 +4230,14 @@
     return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace;
 }
 
+bool Layer::isFrontBuffered() const {
+    if (mBufferInfo.mBuffer == nullptr) {
+        return false;
+    }
+
+    return mBufferInfo.mBuffer->getUsage() & AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
+}
+
 ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) {
     ui::Dataspace updatedDataspace = dataspace;
     // translate legacy dataspaces to modern dataspaces
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index dd91adc..f715910 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -342,6 +342,8 @@
     //
     ui::Dataspace getDataSpace() const;
 
+    virtual bool isFrontBuffered() const;
+
     virtual sp<LayerFE> getCompositionEngineLayerFE() const;
     virtual sp<LayerFE> copyCompositionEngineLayerFE() const;
     sp<LayerFE> getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
@@ -433,13 +435,10 @@
     void updateCloneBufferInfo();
     uint64_t mPreviousFrameNumber = 0;
 
-    /*
-     * called after composition.
-     * returns true if the layer latched a new buffer this frame.
-     */
-    void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& /*glDoneFence*/,
-                           const std::shared_ptr<FenceTime>& /*presentFence*/,
-                           const CompositorTiming&);
+    void onCompositionPresented(const DisplayDevice*,
+                                const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+                                const std::shared_ptr<FenceTime>& /*presentFence*/,
+                                const CompositorTiming&);
 
     // If a buffer was replaced this frame, release the former buffer
     void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/);
@@ -915,14 +914,13 @@
     void recordLayerHistoryBufferUpdate(const scheduler::LayerProps&, nsecs_t now);
     void recordLayerHistoryAnimationTx(const scheduler::LayerProps&, nsecs_t now);
     auto getLayerProps() const {
-        return scheduler::LayerProps{
-                .visible = isVisible(),
-                .bounds = getBounds(),
-                .transform = getTransform(),
-                .setFrameRateVote = getFrameRateForLayerTree(),
-                .frameRateSelectionPriority = getFrameRateSelectionPriority(),
-                .isSmallDirty = mSmallDirty,
-        };
+        return scheduler::LayerProps{.visible = isVisible(),
+                                     .bounds = getBounds(),
+                                     .transform = getTransform(),
+                                     .setFrameRateVote = getFrameRateForLayerTree(),
+                                     .frameRateSelectionPriority = getFrameRateSelectionPriority(),
+                                     .isSmallDirty = mSmallDirty,
+                                     .isFrontBuffered = isFrontBuffered()};
     };
     bool hasBuffer() const { return mBufferInfo.mBuffer != nullptr; }
     void setTransformHint(std::optional<ui::Transform::RotationFlags> transformHint) {
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 21bbb08..8fc9cba 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -51,6 +51,11 @@
         return true;
     }
 
+    // Make all front buffered layers active
+    if (FlagManager::getInstance().vrr_config() && info.isFrontBuffered() && info.isVisible()) {
+        return true;
+    }
+
     return info.isVisible() && info.getLastUpdatedTime() >= threshold;
 }
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 54e9022..8d18769 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -334,6 +334,14 @@
         return votes;
     }
 
+    // Vote for max refresh rate whenever we're front-buffered.
+    if (FlagManager::getInstance().vrr_config() && isFrontBuffered()) {
+        ATRACE_FORMAT_INSTANT("front buffered");
+        ALOGV("%s is front-buffered", mName.c_str());
+        votes.push_back({LayerHistory::LayerVoteType::Max, Fps()});
+        return votes;
+    }
+
     const LayerInfo::Frequent frequent = isFrequent(now);
     mIsFrequencyConclusive = frequent.isConclusive;
     if (!frequent.isFrequent) {
@@ -394,6 +402,10 @@
     return mLayerProps->frameRateSelectionPriority;
 }
 
+bool LayerInfo::isFrontBuffered() const {
+    return mLayerProps->isFrontBuffered;
+}
+
 FloatRect LayerInfo::getBounds() const {
     return mLayerProps->bounds;
 }
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 7d3cffa..03ab0df 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -200,6 +200,7 @@
     FrameRate getSetFrameRateVote() const;
     bool isVisible() const;
     int32_t getFrameRateSelectionPriority() const;
+    bool isFrontBuffered() const;
     FloatRect getBounds() const;
     ui::Transform getTransform() const;
 
@@ -360,6 +361,7 @@
     LayerInfo::FrameRate setFrameRateVote;
     int32_t frameRateSelectionPriority = -1;
     bool isSmallDirty = false;
+    bool isFrontBuffered = false;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index d3db523..56a4ae2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -1178,7 +1178,7 @@
     }
 }
 
-bool Scheduler::onPostComposition(nsecs_t presentTime) {
+bool Scheduler::onCompositionPresented(nsecs_t presentTime) {
     std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
     if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
         if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a5a5e8d..a02180a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -282,8 +282,8 @@
     // Notifies the scheduler about a refresh rate timeline change.
     void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
 
-    // Notifies the scheduler post composition. Returns if recomposite is needed.
-    bool onPostComposition(nsecs_t presentTime);
+    // Notifies the scheduler once the composition is presented. Returns if recomposite is needed.
+    bool onCompositionPresented(nsecs_t presentTime);
 
     // Notifies the scheduler when the display size has changed. Called from SF's main thread
     void onActiveDisplayAreaChanged(uint32_t displayArea);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 186a6bc..3e7ec49 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -38,19 +38,16 @@
 
 namespace {
 
-nsecs_t getExpectedCallbackTime(nsecs_t now, nsecs_t nextVsyncTime,
+nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
                                 const VSyncDispatch::ScheduleTiming& timing) {
-    const auto expectedCallbackTime = nextVsyncTime - timing.readyDuration - timing.workDuration;
-    const auto baseTime =
-            FlagManager::getInstance().dont_skip_on_early() ? now : expectedCallbackTime;
-    return std::max(baseTime, expectedCallbackTime);
+    return nextVsyncTime - timing.readyDuration - timing.workDuration;
 }
 
 nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now,
                                 const VSyncDispatch::ScheduleTiming& timing) {
     const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
             std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
-    return getExpectedCallbackTime(now, nextVsyncTime, timing);
+    return getExpectedCallbackTime(nextVsyncTime, timing);
 }
 
 } // namespace
@@ -106,21 +103,23 @@
             mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
     if (FlagManager::getInstance().dont_skip_on_early()) {
         if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
-            return getExpectedCallbackTime(now, mArmedInfo->mActualVsyncTime, timing);
+            nextVsyncTime = mArmedInfo->mActualVsyncTime;
+        } else {
+            nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
         }
+        nextWakeupTime = std::max(now, nextVsyncTime - timing.workDuration - timing.readyDuration);
     } else {
         if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
-            return getExpectedCallbackTime(now, nextVsyncTime, timing);
+            return getExpectedCallbackTime(nextVsyncTime, timing);
         }
+        nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
+        nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
     }
 
-    nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
-    nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
-
     auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
     mScheduleTiming = timing;
     mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
-    return getExpectedCallbackTime(now, nextVsyncTime, timing);
+    return nextWakeupTime;
 }
 
 void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b1d8db5..15cae33 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2247,6 +2247,7 @@
                 .setFrameRateVote = snapshot->frameRate,
                 .frameRateSelectionPriority = snapshot->frameRateSelectionPriority,
                 .isSmallDirty = snapshot->isSmallDirty,
+                .isFrontBuffered = snapshot->isFrontBuffered(),
         };
 
         if (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) {
@@ -2747,11 +2748,11 @@
         mPowerAdvisor->reportActualWorkDuration();
     }
 
-    if (mScheduler->onPostComposition(presentTime)) {
+    if (mScheduler->onCompositionPresented(presentTime)) {
         scheduleComposite(FrameHint::kNone);
     }
 
-    postComposition(pacesetterId, frameTargeters, presentTime);
+    onCompositionPresented(pacesetterId, frameTargeters, presentTime);
 
     const bool hadGpuComposited =
             multiDisplayUnion(mCompositionCoverage).test(CompositionCoverage::Gpu);
@@ -2908,9 +2909,9 @@
     return ui::ROTATION_0;
 }
 
-void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
-                                     const scheduler::FrameTargeters& frameTargeters,
-                                     nsecs_t presentStartTime) {
+void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId,
+                                            const scheduler::FrameTargeters& frameTargeters,
+                                            nsecs_t presentStartTime) {
     ATRACE_CALL();
     ALOGV(__func__);
 
@@ -3004,8 +3005,9 @@
     mLayersWithBuffersRemoved.clear();
 
     for (const auto& layer: mLayersWithQueuedFrames) {
-        layer->onPostComposition(pacesetterDisplay.get(), pacesetterGpuCompositionDoneFenceTime,
-                                 pacesetterPresentFenceTime, compositorTiming);
+        layer->onCompositionPresented(pacesetterDisplay.get(),
+                                      pacesetterGpuCompositionDoneFenceTime,
+                                      pacesetterPresentFenceTime, compositorTiming);
         layer->releasePendingBuffer(presentTime.ns());
     }
 
@@ -4899,6 +4901,7 @@
                         .transform = layer->getTransform(),
                         .setFrameRateVote = layer->getFrameRateForLayerTree(),
                         .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(),
+                        .isFrontBuffered = layer->isFrontBuffered(),
                 };
                 layer->recordLayerHistoryAnimationTx(layerProps, now);
             }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 94eedc8..1e90340 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -987,8 +987,8 @@
     /*
      * Compositing
      */
-    void postComposition(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&,
-                         nsecs_t presentStartTime) REQUIRES(kMainThreadContext);
+    void onCompositionPresented(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&,
+                                nsecs_t presentStartTime) REQUIRES(kMainThreadContext);
 
     /*
      * Display management
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 70ce884..9b2d453 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -614,8 +614,8 @@
             mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp));
 
             scheduler::FrameTargeter frameTargeter(displayId, mFdp.ConsumeBool());
-            mFlinger->postComposition(displayId, ftl::init::map(displayId, &frameTargeter),
-                                      mFdp.ConsumeIntegral<nsecs_t>());
+            mFlinger->onCompositionPresented(displayId, ftl::init::map(displayId, &frameTargeter),
+                                             mFdp.ConsumeIntegral<nsecs_t>());
         }
 
         mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 39a7ee5..7aae3c4 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -133,7 +133,7 @@
                             ui::LayerStack::fromValue(mFdp.ConsumeIntegral<uint32_t>()));
 
     layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
-    layer->onPostComposition(nullptr, fenceTime, fenceTime, compositorTiming);
+    layer->onCompositionPresented(nullptr, fenceTime, fenceTime, compositorTiming);
 
     layer->setTransform(mFdp.ConsumeIntegral<uint32_t>());
     layer->setTransformToDisplayInverse(mFdp.ConsumeBool());
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index 19d194f..a81f9b8 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -52,4 +52,21 @@
   description: "Feature flag for SmallAreaDetection"
   bug: "283055450"
   is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+  name: "hotplug2"
+  namespace: "core_graphics"
+  description: "Feature flag for using hotplug2 HAL API"
+  bug: "303460805"
+  is_fixed_read_only: true
+}
+
+flag {
+  name: "hdcp_level_hal"
+  namespace: "core_graphics"
+  description: "Feature flag for adding a HAL API to commuicate hdcp levels"
+  bug: "285359126"
+  is_fixed_read_only: true
+}
+
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 5328fa3..1adf14f 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -927,6 +927,43 @@
     EXPECT_EQ(1, animatingLayerCount(time));
 }
 
+TEST_F(LayerHistoryTest, frontBufferedLayerVotesMax) {
+    SET_FLAG_FOR_TEST(flags::vrr_config, true);
+    auto layer = createLayer();
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+    EXPECT_CALL(*layer, isFrontBuffered()).WillRepeatedly(Return(true));
+
+    nsecs_t time = systemTime();
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // layer is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+                         LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+    }
+
+    ASSERT_EQ(1, summarizeLayerHistory(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // layer became inactive
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+    ASSERT_EQ(1, summarizeLayerHistory(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+}
+
 TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) {
     auto layer = createLayer();
 
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index 830dcce..047ef5a 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -21,6 +21,7 @@
 
 #include <scheduler/Fps.h>
 
+#include "FlagUtils.h"
 #include "FpsOps.h"
 #include "Scheduler/LayerHistory.h"
 #include "Scheduler/LayerInfo.h"
@@ -28,6 +29,8 @@
 #include "TestableSurfaceFlinger.h"
 #include "mock/MockSchedulerCallback.h"
 
+#include <com_android_graphics_surfaceflinger_flags.h>
+
 namespace android::scheduler {
 
 using android::mock::createDisplayMode;
@@ -69,6 +72,8 @@
 
 namespace {
 
+using namespace com::android::graphics::surfaceflinger;
+
 TEST_F(LayerInfoTest, prefersPresentTime) {
     std::deque<FrameTimeData> frameTimes;
     constexpr auto kExpectedFps = 50_Hz;
@@ -263,5 +268,18 @@
     ASSERT_EQ(actualVotes[0].fps, vote.fps);
 }
 
+TEST_F(LayerInfoTest, isFrontBuffered) {
+    SET_FLAG_FOR_TEST(flags::vrr_config, true);
+    ASSERT_FALSE(layerInfo.isFrontBuffered());
+
+    LayerProps prop = {.isFrontBuffered = true};
+    layerInfo.setLastPresentTime(0, 0, LayerHistory::LayerUpdateType::Buffer, true, prop);
+    ASSERT_TRUE(layerInfo.isFrontBuffered());
+
+    prop.isFrontBuffered = false;
+    layerInfo.setLastPresentTime(0, 0, LayerHistory::LayerUpdateType::Buffer, true, prop);
+    ASSERT_FALSE(layerInfo.isFrontBuffered());
+}
+
 } // namespace
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index e784eb7..57babaf 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -898,4 +898,24 @@
             gui::WindowInfo::InputConfig::TRUSTED_OVERLAY));
 }
 
+TEST_F(LayerSnapshotTest, isFrontBuffered) {
+    setBuffer(1,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(
+                      1U /*width*/, 1U /*height*/, 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888,
+                      GRALLOC_USAGE_HW_TEXTURE | AHARDWAREBUFFER_USAGE_FRONT_BUFFER /*usage*/));
+
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_TRUE(getSnapshot(1)->isFrontBuffered());
+
+    setBuffer(1,
+              std::make_shared<
+                      renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+                                                               1ULL /* bufferId */,
+                                                               HAL_PIXEL_FORMAT_RGBA_8888,
+                                                               GRALLOC_USAGE_HW_TEXTURE /*usage*/));
+
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_FALSE(getSnapshot(1)->isFrontBuffered());
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 00b5bf0..d4d5b32 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -112,7 +112,7 @@
         EXPECT_CALL(*mFlinger.getFrameTracer(),
                     traceFence(layerId, bufferId, frameNumber, presentFence,
                                FrameTracer::FrameEvent::PRESENT_FENCE, /*startTime*/ 0));
-        layer->onPostComposition(nullptr, glDoneFence, presentFence, compositorTiming);
+        layer->onCompositionPresented(nullptr, glDoneFence, presentFence, compositorTiming);
     }
 };
 
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index fbbb4a2..8310866 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -783,7 +783,9 @@
 TEST_F(VSyncDispatchTimerQueueTest, movesCallbackBackwardsAndSkipAScheduledTargetVSync) {
     SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true);
 
-    EXPECT_CALL(mMockClock, alarmAt(_, 500));
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 400)).InSequence(seq);
     CountingCallback cb(mDispatch);
     auto result =
             mDispatch->schedule(cb,
@@ -873,7 +875,9 @@
 TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesAffectSchedulingState) {
     SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true);
 
-    EXPECT_CALL(mMockClock, alarmAt(_, 600));
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 0)).InSequence(seq);
 
     CountingCallback cb(mDispatch);
     auto result =
@@ -1119,6 +1123,7 @@
 
     Sequence seq;
     EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 0)).InSequence(seq);
 
     CountingCallback cb(mDispatch);
 
@@ -1132,7 +1137,7 @@
     ASSERT_THAT(cb.mCalls.size(), Eq(1));
     EXPECT_THAT(cb.mCalls[0], Eq(1000));
     ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
-    EXPECT_THAT(cb.mWakeupTime[0], Eq(600));
+    EXPECT_THAT(cb.mWakeupTime[0], Eq(0));
     ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
     EXPECT_THAT(cb.mReadyTime[0], Eq(1000));
 }
@@ -1161,7 +1166,9 @@
 TEST_F(VSyncDispatchTimerQueueTest, dontskipAVsyc) {
     SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true);
 
-    EXPECT_CALL(mMockClock, alarmAt(_, 500));
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 300)).InSequence(seq);
     CountingCallback cb(mDispatch);
     auto result =
             mDispatch->schedule(cb,
@@ -1177,6 +1184,11 @@
 
     advanceToNextCallback();
     ASSERT_THAT(cb.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb.mCalls[0], Eq(1000));
+    ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
+    EXPECT_THAT(cb.mWakeupTime[0], Eq(300));
+    ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
+    EXPECT_THAT(cb.mReadyTime[0], Eq(1000));
 }
 
 class VSyncDispatchTimerQueueEntryTest : public testing::Test {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 4cc78fe..3dfb649 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -37,6 +37,7 @@
     MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, scheduler::FrameRateCompatibility());
     MOCK_CONST_METHOD0(getOwnerUid, uid_t());
     MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
+    MOCK_METHOD(bool, isFrontBuffered, (), (const, override));
 };
 
 } // namespace android::mock