Merge "Remove unused private Choreographer apis."
diff --git a/libs/binder/ParcelValTypes.h b/libs/binder/ParcelValTypes.h
index 666d22a..80736c8 100644
--- a/libs/binder/ParcelValTypes.h
+++ b/libs/binder/ParcelValTypes.h
@@ -27,18 +27,32 @@
     VAL_PARCELABLE = 4,
     VAL_SHORT = 5,
     VAL_LONG = 6,
+    VAL_FLOAT = 7,
     VAL_DOUBLE = 8,
     VAL_BOOLEAN = 9,
+    VAL_CHARSEQUENCE = 10,
+    VAL_LIST = 11,
+    VAL_SPARSEARRAY = 12,
     VAL_BYTEARRAY = 13,
     VAL_STRINGARRAY = 14,
     VAL_IBINDER = 15,
+    VAL_PARCELABLEARRAY = 16,
+    VAL_OBJECTARRAY = 17,
     VAL_INTARRAY = 18,
     VAL_LONGARRAY = 19,
     VAL_BYTE = 20,
     VAL_SERIALIZABLE = 21,
+    VAL_SPARSEBOOLEANARRAY = 22,
     VAL_BOOLEANARRAY = 23,
+    VAL_CHARSEQUENCEARRAY = 24,
     VAL_PERSISTABLEBUNDLE = 25,
+    VAL_SIZE = 26,
+    VAL_SIZEF = 27,
     VAL_DOUBLEARRAY = 28,
+    VAL_CHAR = 29,
+    VAL_SHORTARRAY = 30,
+    VAL_CHARARRAY = 31,
+    VAL_FLOATARRAY = 32,
 };
 
 } // namespace binder
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index ba2920e..44b588b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "RpcServer"
 
+#include <inttypes.h>
 #include <poll.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -38,6 +39,8 @@
 
 namespace android {
 
+constexpr size_t kSessionIdBytes = 32;
+
 using base::ScopeGuard;
 using base::unique_fd;
 
@@ -289,13 +292,19 @@
     std::vector<uint8_t> sessionId;
     if (status == OK) {
         if (header.sessionIdSize > 0) {
-            sessionId.resize(header.sessionIdSize);
-            status = client->interruptableReadFully(server->mShutdownTrigger.get(),
-                                                    sessionId.data(), sessionId.size(), {});
-            if (status != OK) {
-                ALOGE("Failed to read session ID for client connecting to RPC server: %s",
-                      statusToString(status).c_str());
-                // still need to cleanup before we can return
+            if (header.sessionIdSize == kSessionIdBytes) {
+                sessionId.resize(header.sessionIdSize);
+                status = client->interruptableReadFully(server->mShutdownTrigger.get(),
+                                                        sessionId.data(), sessionId.size(), {});
+                if (status != OK) {
+                    ALOGE("Failed to read session ID for client connecting to RPC server: %s",
+                          statusToString(status).c_str());
+                    // still need to cleanup before we can return
+                }
+            } else {
+                ALOGE("Malformed session ID. Expecting session ID of size %zu but got %" PRIu16,
+                      kSessionIdBytes, header.sessionIdSize);
+                status = BAD_VALUE;
             }
         }
     }
@@ -353,8 +362,7 @@
             // Uniquely identify session at the application layer. Even if a
             // client/server use the same certificates, if they create multiple
             // sessions, we still want to distinguish between them.
-            constexpr size_t kSessionIdSize = 32;
-            sessionId.resize(kSessionIdSize);
+            sessionId.resize(kSessionIdBytes);
             size_t tries = 0;
             do {
                 // don't block if there is some entropy issue
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 86cc91c..ef62f20 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -183,6 +183,10 @@
 
 status_t RpcState::flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
                                          const sp<IBinder>& binder) {
+    // We can flush all references when the binder is destroyed. No need to send
+    // extra reference counting packets now.
+    if (binder->remoteBinder()) return OK;
+
     std::unique_lock<std::mutex> _l(mNodeMutex);
     if (mTerminated) return DEAD_OBJECT;
 
@@ -192,20 +196,19 @@
     LOG_ALWAYS_FATAL_IF(it->second.binder != binder,
                         "Caller of flushExcessBinderRefs using inconsistent arguments");
 
-    // if this is a local binder, then we want to get rid of all refcounts
-    // (tell the other process it can drop the binder when it wants to - we
-    // have a local sp<>, so we will drop it when we want to as well). if
-    // this is a remote binder, then we need to hold onto one refcount until
-    // it is dropped in BpBinder::onLastStrongRef
-    size_t targetRecd = binder->localBinder() ? 0 : 1;
+    LOG_ALWAYS_FATAL_IF(it->second.timesSent <= 0, "Local binder must have been sent %p",
+                        binder.get());
 
-    // We have timesRecd RPC refcounts, but we only need to hold on to one
-    // when we keep the object. All additional dec strongs are sent
-    // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
-    if (it->second.timesRecd != targetRecd) {
+    // For a local binder, we only need to know that we sent it. Now that we
+    // have an sp<> for this call, we don't need anything more. If the other
+    // process is done with this binder, it needs to know we received the
+    // refcount associated with this call, so we can acknowledge that we
+    // received it. Once (or if) it has no other refcounts, it would reply with
+    // its own decStrong so that it could be removed from this session.
+    if (it->second.timesRecd != 0) {
         _l.unlock();
 
-        return session->sendDecStrongToTarget(address, targetRecd);
+        return session->sendDecStrongToTarget(address, 0);
     }
 
     return OK;
@@ -882,12 +885,6 @@
         }
     }
 
-    // Binder refs are flushed for oneway calls only after all calls which are
-    // built up are executed. Otherwise, they fill up the binder buffer.
-    if (addr != 0 && replyStatus == OK && !oneway) {
-        replyStatus = flushExcessBinderRefs(session, addr, target);
-    }
-
     if (oneway) {
         if (replyStatus != OK) {
             ALOGW("Oneway call failed with error: %d", replyStatus);
@@ -947,6 +944,12 @@
         return OK;
     }
 
+    // Binder refs are flushed for oneway calls only after all calls which are
+    // built up are executed. Otherwise, they fill up the binder buffer.
+    if (addr != 0 && replyStatus == OK) {
+        replyStatus = flushExcessBinderRefs(session, addr, target);
+    }
+
     LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
                                         sizeof(RpcWireReply) <
                                 reply.dataSize(),
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 43533c5..782328d 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -289,7 +289,7 @@
 /**
  * Built-in transaction for all binder objects. This sends a transaction that will immediately
  * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
- * sanity check.
+ * consistency check.
  *
  * Available since API level 29.
  *
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 6bf6e92..f8718aa 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -96,7 +96,7 @@
     auto cert = android::makeSelfSignedCert(pkey.get(), android::kCertValidSeconds);
     CHECK_NE(cert.get(), nullptr);
 
-    auto verifier = std::make_shared<RpcCertificateVerifierNoOp>();
+    auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(OK);
     auto auth = std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
     return RpcTransportCtxFactoryTls::make(verifier, std::move(auth));
 }
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
index cbf11bf..094addd 100644
--- a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -80,7 +80,11 @@
 // A RpcCertificateVerifier that does not verify anything.
 class RpcCertificateVerifierNoOp : public RpcCertificateVerifier {
 public:
-    status_t verify(const SSL*, uint8_t*) override { return OK; }
+    RpcCertificateVerifierNoOp(status_t status) : mStatus(status) {}
+    status_t verify(const SSL*, uint8_t*) override { return mStatus; }
+
+private:
+    status_t mStatus;
 };
 
 } // namespace android
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index be55eba..c0f0a12 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -19,12 +19,19 @@
     srcs: [
         "main.cpp",
     ],
+    // Not using libbinder_tls_shared_deps to use deterministic boringssl libraries.
     static_libs: [
         "libbase",
         "libcutils",
         "liblog",
+        "libbinder_tls_static",
+        "libbinder_tls_test_utils",
+        "libssl_fuzz_unsafe",
+        "libcrypto_fuzz_unsafe",
     ],
-
+    cflags: [
+        "-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE" // for RAND_reset_for_fuzzing
+    ],
     target: {
         android: {
             shared_libs: [
@@ -39,4 +46,8 @@
             ],
         },
     },
+    data: [
+        "server.crt",
+        "server.key",
+    ],
 }
diff --git a/libs/binder/tests/rpc_fuzzer/create_certs.sh b/libs/binder/tests/rpc_fuzzer/create_certs.sh
new file mode 100755
index 0000000..4ae4cb1
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/create_certs.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# As explained in
+#  https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca
+
+openssl genrsa -des3 -passout pass:xxxx -out server.pass.key 2048
+openssl rsa -passin pass:xxxx -in server.pass.key -out server.key
+rm -f server.pass.key
+
+openssl req \
+    -subj "/" \
+    -new -key server.key -out server.csr
+
+openssl x509 -req -sha256 -days 99999 -in server.csr -signkey server.key -out server.crt
+rm -f server.csr
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index c848798..518849a 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -13,13 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <binder/Binder.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
 #include <fuzzer/FuzzedDataProvider.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
 
 #include <sys/resource.h>
 #include <sys/un.h>
@@ -51,13 +58,66 @@
     }
 };
 
+int passwordCallback(char* buf, int size, int /*rwflag*/, void* /*u*/) {
+    constexpr const char pass[] = "xxxx"; // See create_certs.sh
+    if (size <= 0) return 0;
+    int numCopy = std::min<int>(size, sizeof(pass));
+    (void)memcpy(buf, pass, numCopy);
+    return numCopy;
+}
+
+struct ServerAuth {
+    bssl::UniquePtr<EVP_PKEY> pkey;
+    bssl::UniquePtr<X509> cert;
+};
+
+// Use pre-configured keys because runtime generated keys / certificates are not
+// deterministic, and the algorithm is time consuming.
+ServerAuth readServerKeyAndCert() {
+    ServerAuth ret;
+
+    auto keyPath = android::base::GetExecutableDirectory() + "/data/server.key";
+    bssl::UniquePtr<BIO> keyBio(BIO_new_file(keyPath.c_str(), "r"));
+    ret.pkey.reset(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, passwordCallback, nullptr));
+    CHECK_NE(ret.pkey.get(), nullptr);
+
+    auto certPath = android::base::GetExecutableDirectory() + "/data/server.crt";
+    bssl::UniquePtr<BIO> certBio(BIO_new_file(certPath.c_str(), "r"));
+    ret.cert.reset(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
+    CHECK_NE(ret.cert.get(), nullptr);
+
+    return ret;
+}
+
+std::unique_ptr<RpcAuth> createServerRpcAuth() {
+    static auto sAuth = readServerKeyAndCert();
+
+    CHECK(EVP_PKEY_up_ref(sAuth.pkey.get()));
+    bssl::UniquePtr<EVP_PKEY> pkey(sAuth.pkey.get());
+    CHECK(X509_up_ref(sAuth.cert.get()));
+    bssl::UniquePtr<X509> cert(sAuth.cert.get());
+
+    return std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
+}
+
+std::unique_ptr<RpcTransportCtxFactory> makeTransportCtxFactory(FuzzedDataProvider* provider) {
+    bool isTls = provider->ConsumeBool();
+    if (!isTls) {
+        return RpcTransportCtxFactoryRaw::make();
+    }
+    status_t verifyStatus = provider->ConsumeIntegral<status_t>();
+    auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(verifyStatus);
+    return RpcTransportCtxFactoryTls::make(verifier, createServerRpcAuth());
+}
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     if (size > 50000) return 0;
     FuzzedDataProvider provider(data, size);
+    RAND_reset_for_fuzzing();
 
     unlink(kSock.c_str());
 
-    sp<RpcServer> server = RpcServer::make();
+    sp<RpcServer> server = RpcServer::make(makeTransportCtxFactory(&provider));
     server->setRootObject(sp<SomeBinder>::make());
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
diff --git a/libs/binder/tests/rpc_fuzzer/server.crt b/libs/binder/tests/rpc_fuzzer/server.crt
new file mode 100644
index 0000000..9142474
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/server.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICiTCCAXECFG1ggXE36l2WXeG6YTnaRVB7EmgQMA0GCSqGSIb3DQEBCwUAMAAw
+IBcNMjEwOTI5MDEzOTEzWhgPMjI5NTA3MTQwMTM5MTNaMAAwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDE3KnhPMwINpP5aIHIo/3GTlROZOK5AmkEsWmP
+w8smSWo2hJ7M0sOhruvOz82WORj48K8C0W72yFN+e9g32qoNMJFP/s6j1RWmaAKZ
+eSQUq6ixyaGhFLBOoukVykfTnY4qn4RbX5HzgpAPR1gv5ELvMXXPrxvtpIcVIrhm
+/dBQIa3iHZS6kypNbmRx/nhDVU8FK9s9WU5VLpbuNxv+m4X4Y1M/VZNatUMx5I0o
+ystV4JTqzjRZRPR4sxtMhu8/A11JsBVLeu8ZM/0IGCjmLOF4hy5a5YDv8MOJtdG2
+LI7ibZNtyrZiKwwhJc3tElzeIFit4T5Xjx69y/EMS4Hwhf3zAgMBAAEwDQYJKoZI
+hvcNAQELBQADggEBAD3gRbUybW7P2CihMyskTgS9HoIT9c02JWjtueWQIiQkyqTB
+6QdUQTHM5weil6TiW8NfpQQUIvrh66Pkph65shvFqxUsjdW25b4RbfUldFihfs1n
+kTa+e+hZONnVuzLvezIs2b8dygH9GA5y2OiLxwrMUcyaoCHGwKF7iOE0SJhfx0kY
+JDs4O+gAVjEsBSc24pm9aHBxgRCiEm1I4+RZf6PRBIz1ZadGBFsCZ+Gj6wyLP2Wq
+kjjMiV6o8pEjJjM+Oi4GfxvNewMCd2hMZYuJYpYC3cc7fPIpx8luidqKJdve8c6m
+KQ+dJ6ZQxEi0Zc9Jzre7NNoVcpIdc8SbkEM/DDo=
+-----END CERTIFICATE-----
diff --git a/libs/binder/tests/rpc_fuzzer/server.key b/libs/binder/tests/rpc_fuzzer/server.key
new file mode 100644
index 0000000..743470e
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAxNyp4TzMCDaT+WiByKP9xk5UTmTiuQJpBLFpj8PLJklqNoSe
+zNLDoa7rzs/NljkY+PCvAtFu9shTfnvYN9qqDTCRT/7Oo9UVpmgCmXkkFKuoscmh
+oRSwTqLpFcpH052OKp+EW1+R84KQD0dYL+RC7zF1z68b7aSHFSK4Zv3QUCGt4h2U
+upMqTW5kcf54Q1VPBSvbPVlOVS6W7jcb/puF+GNTP1WTWrVDMeSNKMrLVeCU6s40
+WUT0eLMbTIbvPwNdSbAVS3rvGTP9CBgo5izheIcuWuWA7/DDibXRtiyO4m2Tbcq2
+YisMISXN7RJc3iBYreE+V48evcvxDEuB8IX98wIDAQABAoIBACcI5jp+NqrOP6st
+uMZTFifzMi5VPMuYmcBPeXIDTc3qsr/ari5JAHeX2rQoakiGS9hYySsS4iDW+g9T
+eT0iA6QX5Ehrawf7YY6cgx9xcOEUZJ/ULlNlacw961/huzpPvHfhJ3qCycryMaSF
+7guZBFivgv/KZgxKGmrrdosdeufYXL3eHWZIrvcN4cDVgxslZg0o3Y5kCW3/KmDO
+QwvBlqgja93yImmkFA5BA/hQUsWuMBiR0xAd4b1NSBVCGTAYuCm6Up+6tIxeBSu5
+MVnNXbAIyVkbAS+gaR4uut6ObzFwUyGKDMaMpJ0LHLbusZy0svevu6Hjx+eH0ePC
+rj1xmDECgYEA4WR+1m3Tej0botG68+pZ8yLBgomSBAqpINCFkMEGQ2sQ1CqMMkHq
+8LAQNotU56W/0/H3eQemE3qBSKt1BUffpCvCHWkL9DRyDNhiq9U2PvV2Lx0Bv77e
+ET5MSDECUjlIsDqnv2qbq/m23BiP7AM8c9s6HjD0PqptyHjLlWHK86kCgYEA35hW
+AZEqMzsTNVQ8lXQtbqCyv8lls1SJbvIf3b5KItw9CwqpLr+UXssXh713j+yMW+WN
+3nv5+VaggkNBa9fHdqQEYT0L52OnLNjsfTlVhP5g2lOIa5VQYb/wqF1TaiZ27SGU
+lmLqiyArZgTnc3yo1wuIRPAbYbbm6CVnz7bm5jsCgYEAqfov7WZF5hnPjaq9YtWJ
+oGLFrLwy8flYMvcOw2vOXWmQ93Be6kfr9jfRAlFxZoEJeb0w9IVgKbBpb3Ree+0I
+K7cUXTmrWi9zE1zcjNnuXuyehElL2F8I+dgRjx/msDujJcQWXbT4UWmxDas4XrTS
+Ek1yNvKUP+4nfNgcMDvf4oECgYEAjgfYajpqEgzukKunqFAaI/HUWdt2zMlgW6dV
+8qdTtH0uEXt+KIHtn6FmmwURk8zxA9b3nWInUeljIBvUzMpOm+BoH9SFYUB+CxDo
+eEsZNdfYchcpyx0X6F/iYTCXMhCo7syr9DN1RVbz+mQXGdcP8ToUH6Zd3l4uozxP
+izRly80CgYEAqz7fCgQH74BwHoroSNdD3Cn6KNVx+oPuwRmzO4xMSOGyd/dNB2NA
+uzzuCTbrzC0jCXpqR0Bh9gYMjxyRZbifPX/YuFHyCIKK4+SQfeC4ZEwmSJVGWeh7
+3NksFJPCH4K3KbLNputByWJWOgKUdy70e/xOi83acBAVyRs+7H9LocE=
+-----END RSA PRIVATE KEY-----
diff --git a/libs/binder/tests/unit_fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
index 6f054d2..8ea948c 100644
--- a/libs/binder/tests/unit_fuzzers/Android.bp
+++ b/libs/binder/tests/unit_fuzzers/Android.bp
@@ -30,16 +30,28 @@
         "-Wall",
         "-Werror",
     ],
-    shared_libs: [
-        "libbinder",
-        "libutils",
-        "libbase",
-    ],
     target: {
+        android: {
+            shared_libs: [
+                "libcutils",
+                "libutils",
+                "libbase",
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libcutils",
+                "liblog",
+                "libutils",
+                "libbase",
+                "libbinder",
+            ],
+        },
         darwin: {
             enabled: false,
-        }
-    }
+        },
+    },
 }
 
 cc_fuzz {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 379b090..14ec948 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -456,10 +456,10 @@
     // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
     incStrong((void*)transactionCallbackThunk);
 
+    const bool sizeHasChanged = mRequestedSize != mSize;
+    mSize = mRequestedSize;
+    const bool updateDestinationFrame = sizeHasChanged || !mLastBufferInfo.hasBuffer;
     Rect crop = computeCrop(bufferItem);
-    const bool updateDestinationFrame =
-            bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE ||
-            !mLastBufferInfo.hasBuffer;
     mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
                            bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
                            bufferItem.mScalingMode, crop);
@@ -468,12 +468,12 @@
             std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
                       std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
                       std::placeholders::_4);
-    t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback);
+    sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
+    t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId,
+                 releaseBufferCallback);
     t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
     t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
     t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
-    t->setAcquireFence(mSurfaceControl,
-                       bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
     t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
     mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
 
@@ -486,7 +486,6 @@
     if (!bufferItem.mIsAutoTimestamp) {
         t->setDesiredPresentTime(bufferItem.mTimestamp);
     }
-    t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
 
     if (!mNextFrameTimelineInfoQueue.empty()) {
         t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front());
@@ -572,7 +571,6 @@
 
 bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
     if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
-        mSize = mRequestedSize;
         // Only reject buffers if scaling mode is freeze.
         return false;
     }
@@ -586,7 +584,6 @@
     }
     ui::Size bufferSize(bufWidth, bufHeight);
     if (mRequestedSize != mSize && mRequestedSize == bufferSize) {
-        mSize = mRequestedSize;
         return false;
     }
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index a419a63..cf61209 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -64,12 +64,10 @@
         frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
         changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS),
         fixedTransformHint(ui::Transform::ROT_INVALID),
-        frameNumber(0),
         autoRefresh(false),
         isTrustedOverlay(false),
         bufferCrop(Rect::INVALID_RECT),
         destinationFrame(Rect::INVALID_RECT),
-        releaseBufferListener(nullptr),
         dropInputMode(gui::DropInputMode::NONE) {
     matrix.dsdx = matrix.dtdy = 1.0f;
     matrix.dsdy = matrix.dtdx = 0.0f;
@@ -104,20 +102,6 @@
     SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
     SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
 
-    if (buffer) {
-        SAFE_PARCEL(output.writeBool, true);
-        SAFE_PARCEL(output.write, *buffer);
-    } else {
-        SAFE_PARCEL(output.writeBool, false);
-    }
-
-    if (acquireFence) {
-        SAFE_PARCEL(output.writeBool, true);
-        SAFE_PARCEL(output.write, *acquireFence);
-    } else {
-        SAFE_PARCEL(output.writeBool, false);
-    }
-
     SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace));
     SAFE_PARCEL(output.write, hdrMetadata);
     SAFE_PARCEL(output.write, surfaceDamageRegion);
@@ -133,8 +117,6 @@
     SAFE_PARCEL(output.write, colorTransform.asArray(), 16 * sizeof(float));
     SAFE_PARCEL(output.writeFloat, cornerRadius);
     SAFE_PARCEL(output.writeUint32, backgroundBlurRadius);
-    SAFE_PARCEL(output.writeStrongBinder, cachedBuffer.token.promote());
-    SAFE_PARCEL(output.writeUint64, cachedBuffer.id);
     SAFE_PARCEL(output.writeParcelable, metadata);
     SAFE_PARCEL(output.writeFloat, bgColorAlpha);
     SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(bgColorDataspace));
@@ -151,9 +133,7 @@
     SAFE_PARCEL(output.writeByte, frameRateCompatibility);
     SAFE_PARCEL(output.writeByte, changeFrameRateStrategy);
     SAFE_PARCEL(output.writeUint32, fixedTransformHint);
-    SAFE_PARCEL(output.writeUint64, frameNumber);
     SAFE_PARCEL(output.writeBool, autoRefresh);
-    SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener));
 
     SAFE_PARCEL(output.writeUint32, blurRegions.size());
     for (auto region : blurRegions) {
@@ -174,8 +154,8 @@
     SAFE_PARCEL(output.write, destinationFrame);
     SAFE_PARCEL(output.writeBool, isTrustedOverlay);
 
-    SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
     SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
+    SAFE_PARCEL(bufferData.write, output);
     return NO_ERROR;
 }
 
@@ -217,19 +197,6 @@
     SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
     SAFE_PARCEL(input.read, orientedDisplaySpaceRect);
 
-    bool tmpBool = false;
-    SAFE_PARCEL(input.readBool, &tmpBool);
-    if (tmpBool) {
-        buffer = new GraphicBuffer();
-        SAFE_PARCEL(input.read, *buffer);
-    }
-
-    SAFE_PARCEL(input.readBool, &tmpBool);
-    if (tmpBool) {
-        acquireFence = new Fence();
-        SAFE_PARCEL(input.read, *acquireFence);
-    }
-
     uint32_t tmpUint32 = 0;
     SAFE_PARCEL(input.readUint32, &tmpUint32);
     dataspace = static_cast<ui::Dataspace>(tmpUint32);
@@ -237,6 +204,8 @@
     SAFE_PARCEL(input.read, hdrMetadata);
     SAFE_PARCEL(input.read, surfaceDamageRegion);
     SAFE_PARCEL(input.readInt32, &api);
+
+    bool tmpBool = false;
     SAFE_PARCEL(input.readBool, &tmpBool);
     if (tmpBool) {
         sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
@@ -245,10 +214,6 @@
     SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float));
     SAFE_PARCEL(input.readFloat, &cornerRadius);
     SAFE_PARCEL(input.readUint32, &backgroundBlurRadius);
-    sp<IBinder> tmpBinder;
-    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
-    cachedBuffer.token = tmpBinder;
-    SAFE_PARCEL(input.readUint64, &cachedBuffer.id);
     SAFE_PARCEL(input.readParcelable, &metadata);
 
     SAFE_PARCEL(input.readFloat, &bgColorAlpha);
@@ -273,15 +238,8 @@
     SAFE_PARCEL(input.readByte, &changeFrameRateStrategy);
     SAFE_PARCEL(input.readUint32, &tmpUint32);
     fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
-    SAFE_PARCEL(input.readUint64, &frameNumber);
     SAFE_PARCEL(input.readBool, &autoRefresh);
 
-    tmpBinder = nullptr;
-    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
-    if (tmpBinder) {
-        releaseBufferListener = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
-    }
-
     uint32_t numRegions = 0;
     SAFE_PARCEL(input.readUint32, &numRegions);
     blurRegions.clear();
@@ -305,11 +263,10 @@
     SAFE_PARCEL(input.read, destinationFrame);
     SAFE_PARCEL(input.readBool, &isTrustedOverlay);
 
-    SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
-
     uint32_t mode;
     SAFE_PARCEL(input.readUint32, &mode);
     dropInputMode = static_cast<gui::DropInputMode>(mode);
+    SAFE_PARCEL(bufferData.read, input);
     return NO_ERROR;
 }
 
@@ -460,12 +417,7 @@
     }
     if (other.what & eBufferChanged) {
         what |= eBufferChanged;
-        buffer = other.buffer;
-        releaseBufferEndpoint = other.releaseBufferEndpoint;
-    }
-    if (other.what & eAcquireFenceChanged) {
-        what |= eAcquireFenceChanged;
-        acquireFence = other.acquireFence;
+        bufferData = other.bufferData;
     }
     if (other.what & eDataspaceChanged) {
         what |= eDataspaceChanged;
@@ -498,10 +450,6 @@
         what |= eInputInfoChanged;
         windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle);
     }
-    if (other.what & eCachedBufferChanged) {
-        what |= eCachedBufferChanged;
-        cachedBuffer = other.cachedBuffer;
-    }
     if (other.what & eBackgroundColorChanged) {
         what |= eBackgroundColorChanged;
         color = other.color;
@@ -530,10 +478,6 @@
         what |= eFixedTransformHintChanged;
         fixedTransformHint = other.fixedTransformHint;
     }
-    if (other.what & eFrameNumberChanged) {
-        what |= eFrameNumberChanged;
-        frameNumber = other.frameNumber;
-    }
     if (other.what & eAutoRefreshChanged) {
         what |= eAutoRefreshChanged;
         autoRefresh = other.autoRefresh;
@@ -542,13 +486,6 @@
         what |= eTrustedOverlayChanged;
         isTrustedOverlay = other.isTrustedOverlay;
     }
-    if (other.what & eReleaseBufferListenerChanged) {
-        if (releaseBufferListener) {
-            ALOGW("Overriding releaseBufferListener");
-        }
-        what |= eReleaseBufferListenerChanged;
-        releaseBufferListener = other.releaseBufferListener;
-    }
     if (other.what & eStretchChanged) {
         what |= eStretchChanged;
         stretchEffect = other.stretchEffect;
@@ -576,11 +513,11 @@
 }
 
 bool layer_state_t::hasBufferChanges() const {
-    return (what & layer_state_t::eBufferChanged) || (what & layer_state_t::eCachedBufferChanged);
+    return what & layer_state_t::eBufferChanged;
 }
 
 bool layer_state_t::hasValidBuffer() const {
-    return buffer || cachedBuffer.isValid();
+    return bufferData.buffer || bufferData.cachedBuffer.isValid();
 }
 
 status_t layer_state_t::matrix22_t::write(Parcel& output) const {
@@ -741,4 +678,66 @@
     return NO_ERROR;
 }
 
+status_t BufferData::write(Parcel& output) const {
+    SAFE_PARCEL(output.writeInt32, flags.get());
+
+    if (buffer) {
+        SAFE_PARCEL(output.writeBool, true);
+        SAFE_PARCEL(output.write, *buffer);
+    } else {
+        SAFE_PARCEL(output.writeBool, false);
+    }
+
+    if (acquireFence) {
+        SAFE_PARCEL(output.writeBool, true);
+        SAFE_PARCEL(output.write, *acquireFence);
+    } else {
+        SAFE_PARCEL(output.writeBool, false);
+    }
+
+    SAFE_PARCEL(output.writeUint64, frameNumber);
+    SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener));
+    SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
+
+    SAFE_PARCEL(output.writeStrongBinder, cachedBuffer.token.promote());
+    SAFE_PARCEL(output.writeUint64, cachedBuffer.id);
+
+    return NO_ERROR;
+}
+
+status_t BufferData::read(const Parcel& input) {
+    int32_t tmpInt32;
+    SAFE_PARCEL(input.readInt32, &tmpInt32);
+    flags = Flags<BufferDataChange>(tmpInt32);
+
+    bool tmpBool = false;
+    SAFE_PARCEL(input.readBool, &tmpBool);
+    if (tmpBool) {
+        buffer = new GraphicBuffer();
+        SAFE_PARCEL(input.read, *buffer);
+    }
+
+    SAFE_PARCEL(input.readBool, &tmpBool);
+    if (tmpBool) {
+        acquireFence = new Fence();
+        SAFE_PARCEL(input.read, *acquireFence);
+    }
+
+    SAFE_PARCEL(input.readUint64, &frameNumber);
+
+    sp<IBinder> tmpBinder = nullptr;
+    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+    if (tmpBinder) {
+        releaseBufferListener = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
+    }
+    SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
+
+    tmpBinder = nullptr;
+    SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+    cachedBuffer.token = tmpBinder;
+    SAFE_PARCEL(input.readUint64, &cachedBuffer.id);
+
+    return NO_ERROR;
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index bbd3cca..aca59b6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -805,7 +805,7 @@
         layer_state_t* s = &(mComposerStates[handle].state);
         if (!(s->what & layer_state_t::eBufferChanged)) {
             continue;
-        } else if (s->what & layer_state_t::eCachedBufferChanged) {
+        } else if (s->bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged)) {
             // If eBufferChanged and eCachedBufferChanged are both trued then that means
             // we already cached the buffer in a previous call to cacheBuffers, perhaps
             // from writeToParcel on a Transaction that was merged in to this one.
@@ -814,23 +814,22 @@
 
         // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste
         // time trying to cache them.
-        if (!s->buffer) {
+        if (!s->bufferData.buffer) {
             continue;
         }
 
         uint64_t cacheId = 0;
-        status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
+        status_t ret = BufferCache::getInstance().getCacheId(s->bufferData.buffer, &cacheId);
         if (ret == NO_ERROR) {
             // Cache-hit. Strip the buffer and send only the id.
-            s->what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged);
-            s->buffer = nullptr;
+            s->bufferData.buffer = nullptr;
         } else {
             // Cache-miss. Include the buffer and send the new cacheId.
-            cacheId = BufferCache::getInstance().cache(s->buffer);
+            cacheId = BufferCache::getInstance().cache(s->bufferData.buffer);
         }
-        s->what |= layer_state_t::eCachedBufferChanged;
-        s->cachedBuffer.token = BufferCache::getInstance().getToken();
-        s->cachedBuffer.id = cacheId;
+        s->bufferData.flags |= BufferData::BufferDataChange::cachedBufferChanged;
+        s->bufferData.cachedBuffer.token = BufferCache::getInstance().getToken();
+        s->bufferData.cachedBuffer.id = cacheId;
 
         // If we have more buffers than the size of the cache, we should stop caching so we don't
         // evict other buffers in this transaction
@@ -1289,22 +1288,33 @@
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
-        const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer, const ReleaseCallbackId& id,
-        ReleaseBufferCallback callback) {
+        const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
+        const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber,
+        const ReleaseCallbackId& id, ReleaseBufferCallback callback) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
     removeReleaseBufferCallback(s);
-    s->what |= layer_state_t::eBufferChanged;
-    s->buffer = buffer;
-    s->releaseBufferEndpoint = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    BufferData bufferData;
+    bufferData.buffer = buffer;
+    if (frameNumber) {
+        bufferData.frameNumber = *frameNumber;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+    }
+    if (fence) {
+        bufferData.acquireFence = *fence;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+    }
+    bufferData.releaseBufferEndpoint =
+            IInterface::asBinder(TransactionCompletedListener::getIInstance());
     if (mIsAutoTimestamp) {
         mDesiredPresentTime = systemTime();
     }
-    setReleaseBufferCallback(s, id, callback);
-
+    setReleaseBufferCallback(&bufferData, id, callback);
+    s->what |= layer_state_t::eBufferChanged;
+    s->bufferData = bufferData;
     registerSurfaceControlForCallback(sc);
 
     mContainsBuffer = true;
@@ -1312,51 +1322,33 @@
 }
 
 void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) {
-    if (!s->releaseBufferListener) {
+    if (!(s->what & layer_state_t::eBufferChanged)) {
         return;
     }
 
-    s->what &= ~static_cast<uint64_t>(layer_state_t::eReleaseBufferListenerChanged);
-    s->releaseBufferListener = nullptr;
     auto listener = TransactionCompletedListener::getInstance();
-    listener->removeReleaseBufferCallback(s->releaseCallbackId);
-    s->releaseCallbackId = ReleaseCallbackId::INVALID_ID;
+    listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId);
 }
 
-void SurfaceComposerClient::Transaction::setReleaseBufferCallback(layer_state_t* s,
+void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData,
                                                                   const ReleaseCallbackId& id,
                                                                   ReleaseBufferCallback callback) {
     if (!callback) {
         return;
     }
 
-    if (!s->buffer) {
+    if (!bufferData->buffer) {
         ALOGW("Transaction::setReleaseBufferCallback"
               "ignored trying to set a callback on a null buffer.");
         return;
     }
 
-    s->what |= layer_state_t::eReleaseBufferListenerChanged;
-    s->releaseBufferListener = TransactionCompletedListener::getIInstance();
-    s->releaseCallbackId = id;
+    bufferData->releaseBufferListener = TransactionCompletedListener::getIInstance();
+    bufferData->releaseCallbackId = id;
     auto listener = TransactionCompletedListener::getInstance();
     listener->setReleaseBufferCallback(id, callback);
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
-        const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
-    layer_state_t* s = getLayerState(sc);
-    if (!s) {
-        mStatus = BAD_INDEX;
-        return *this;
-    }
-    s->what |= layer_state_t::eAcquireFenceChanged;
-    s->acquireFence = fence;
-
-    registerSurfaceControlForCallback(sc);
-    return *this;
-}
-
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace(
         const sp<SurfaceControl>& sc, ui::Dataspace dataspace) {
     layer_state_t* s = getLayerState(sc);
@@ -1506,20 +1498,6 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameNumber(
-        const sp<SurfaceControl>& sc, uint64_t frameNumber) {
-    layer_state_t* s = getLayerState(sc);
-    if (!s) {
-        mStatus = BAD_INDEX;
-        return *this;
-    }
-
-    s->what |= layer_state_t::eFrameNumberChanged;
-    s->frameNumber = frameNumber;
-
-    return *this;
-}
-
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
         const sp<SurfaceControl>& sc, const WindowInfo& info) {
     layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index b27102b..1f5d289 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -58,6 +58,44 @@
     bool isValid() const { return token != nullptr; }
 };
 
+struct BufferData {
+    enum class BufferDataChange : uint32_t {
+        fenceChanged = 0x01,
+        frameNumberChanged = 0x02,
+        cachedBufferChanged = 0x04,
+    };
+
+    sp<GraphicBuffer> buffer;
+    sp<Fence> acquireFence;
+
+    // Used by BlastBufferQueue to forward the framenumber generated by the
+    // graphics producer.
+    uint64_t frameNumber = 0;
+
+    // Listens to when the buffer is safe to be released. This is used for blast
+    // layers only. The callback includes a release fence as well as the graphic
+    // buffer id to identify the buffer.
+    sp<ITransactionCompletedListener> releaseBufferListener = nullptr;
+
+    // Keeps track of the release callback id associated with the listener. This
+    // is not sent to the server since the id can be reconstructed there. This
+    // is used to remove the old callback from the client process map if it is
+    // overwritten by another setBuffer call.
+    ReleaseCallbackId releaseCallbackId = ReleaseCallbackId::INVALID_ID;
+
+    // Stores which endpoint the release information should be sent to. We don't want to send the
+    // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
+    // was called with.
+    sp<IBinder> releaseBufferEndpoint;
+
+    Flags<BufferDataChange> flags;
+
+    client_cache_t cachedBuffer;
+
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
+};
+
 /*
  * Used to communicate layer information between SurfaceFlinger and its clients.
  */
@@ -82,7 +120,7 @@
         eTransparentRegionChanged = 0x00000020,
         eFlagsChanged = 0x00000040,
         eLayerStackChanged = 0x00000080,
-        eReleaseBufferListenerChanged = 0x00000400,
+        /* unused 0x00000400, */
         eShadowRadiusChanged = 0x00000800,
         eLayerCreated = 0x00001000,
         eBufferCropChanged = 0x00002000,
@@ -94,7 +132,7 @@
         eTransformToDisplayInverseChanged = 0x00080000,
         eCropChanged = 0x00100000,
         eBufferChanged = 0x00200000,
-        eAcquireFenceChanged = 0x00400000,
+        /* unused 0x00400000, */
         eDataspaceChanged = 0x00800000,
         eHdrMetadataChanged = 0x01000000,
         eSurfaceDamageRegionChanged = 0x02000000,
@@ -105,7 +143,7 @@
         eInputInfoChanged = 0x40000000,
         eCornerRadiusChanged = 0x80000000,
         eDestinationFrameChanged = 0x1'00000000,
-        eCachedBufferChanged = 0x2'00000000,
+        /* unused = 0x2'00000000, */
         eBackgroundColorChanged = 0x4'00000000,
         eMetadataChanged = 0x8'00000000,
         eColorSpaceAgnosticChanged = 0x10'00000000,
@@ -114,7 +152,7 @@
         eBackgroundBlurRadiusChanged = 0x80'00000000,
         eProducerDisconnect = 0x100'00000000,
         eFixedTransformHintChanged = 0x200'00000000,
-        eFrameNumberChanged = 0x400'00000000,
+        /* unused 0x400'00000000, */
         eBlurRegionsChanged = 0x800'00000000,
         eAutoRefreshChanged = 0x1000'00000000,
         eStretchChanged = 0x2000'00000000,
@@ -169,8 +207,7 @@
     bool transformToDisplayInverse;
     Rect crop;
     Rect orientedDisplaySpaceRect;
-    sp<GraphicBuffer> buffer;
-    sp<Fence> acquireFence;
+    BufferData bufferData;
     ui::Dataspace dataspace;
     HdrMetadata hdrMetadata;
     Region surfaceDamageRegion;
@@ -181,8 +218,6 @@
 
     sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle();
 
-    client_cache_t cachedBuffer;
-
     LayerMetadata metadata;
 
     // The following refer to the alpha, and dataspace, respectively of
@@ -216,10 +251,6 @@
     // otherwise the value will be a valid ui::Rotation.
     ui::Transform::RotationFlags fixedTransformHint;
 
-    // Used by BlastBufferQueue to forward the framenumber generated by the
-    // graphics producer.
-    uint64_t frameNumber;
-
     // Indicates that the consumer should acquire the next frame as soon as it
     // can and not wait for a frame to become available. This is only relevant
     // in shared buffer mode.
@@ -235,22 +266,6 @@
     Rect bufferCrop;
     Rect destinationFrame;
 
-    // Listens to when the buffer is safe to be released. This is used for blast
-    // layers only. The callback includes a release fence as well as the graphic
-    // buffer id to identify the buffer.
-    sp<ITransactionCompletedListener> releaseBufferListener;
-
-    // Keeps track of the release callback id associated with the listener. This
-    // is not sent to the server since the id can be reconstructed there. This
-    // is used to remove the old callback from the client process map if it is
-    // overwritten by another setBuffer call.
-    ReleaseCallbackId releaseCallbackId;
-
-    // Stores which endpoint the release information should be sent to. We don't want to send the
-    // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
-    // was called with.
-    sp<IBinder> releaseBufferEndpoint;
-
     // Force inputflinger to drop all input events for the layer and its children.
     gui::DropInputMode dropInputMode;
 };
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 403ca0a..82249a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -399,8 +399,7 @@
 
         void cacheBuffers();
         void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
-        void setReleaseBufferCallback(layer_state_t*, const ReleaseCallbackId&,
-                                      ReleaseBufferCallback);
+        void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback);
         void removeReleaseBufferCallback(layer_state_t*);
 
     public:
@@ -473,10 +472,10 @@
         Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
                                                   bool transformToDisplayInverse);
         Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
+                               const std::optional<sp<Fence>>& fence = std::nullopt,
+                               const std::optional<uint64_t>& frameNumber = std::nullopt,
                                const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID,
                                ReleaseBufferCallback callback = nullptr);
-        Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
-        Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
         Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
         Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
         Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
@@ -501,8 +500,6 @@
 
         // ONLY FOR BLAST ADAPTER
         Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
-        // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour.
-        Transaction& setFrameNumber(const sp<SurfaceControl>& sc, uint64_t frameNumber);
 
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const gui::WindowInfo& info);
         Transaction& setFocusedWindow(const gui::FocusRequest& request);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 26d902d..b474086 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -672,6 +672,83 @@
                                                /*border*/ 0, /*outsideRegion*/ true));
 }
 
+// b/196339769 verify we can can update the requested size while the in FREEZE scaling mode and
+// scale the buffer properly when the mode changes to SCALE_TO_WINDOW
+TEST_F(BLASTBufferQueueTest, ScalingModeChanges) {
+    uint8_t r = 255;
+    uint8_t g = 0;
+    uint8_t b = 0;
+
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight / 4);
+    sp<IGraphicBufferProducer> igbProducer;
+    setUpProducer(adapter, igbProducer);
+    {
+        int slot;
+        sp<Fence> fence;
+        sp<GraphicBuffer> buf;
+        auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight / 4,
+                                              PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                              nullptr, nullptr);
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+        ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+        uint32_t* bufData;
+        buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+                  reinterpret_cast<void**>(&bufData));
+        fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b);
+        buf->unlock();
+
+        IGraphicBufferProducer::QueueBufferOutput qbOutput;
+        IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+                                                       HAL_DATASPACE_UNKNOWN, {},
+                                                       NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+                                                       Fence::NO_FENCE);
+        igbProducer->queueBuffer(slot, input, &qbOutput);
+        adapter.waitForCallbacks();
+    }
+    // capture screen and verify that it is red
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+
+    ASSERT_NO_FATAL_FAILURE(
+            checkScreenCapture(r, g, b,
+                               {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 4}));
+
+    // update the size to half the display and dequeue a buffer quarter of the display.
+    adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight / 2);
+
+    {
+        int slot;
+        sp<Fence> fence;
+        sp<GraphicBuffer> buf;
+        auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight / 8,
+                                              PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                              nullptr, nullptr);
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+        ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+        uint32_t* bufData;
+        buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+                  reinterpret_cast<void**>(&bufData));
+        g = 255;
+        fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight()), buf->getStride(), r, g, b);
+        buf->unlock();
+
+        IGraphicBufferProducer::QueueBufferOutput qbOutput;
+        IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+                                                       HAL_DATASPACE_UNKNOWN, {},
+                                                       NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+                                                       0, Fence::NO_FENCE);
+        igbProducer->queueBuffer(slot, input, &qbOutput);
+        adapter.waitForCallbacks();
+    }
+    // capture screen and verify that it is red
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+    // verify we still scale the buffer to the new size (half the screen height)
+    ASSERT_NO_FATAL_FAILURE(
+            checkScreenCapture(r, g, b,
+                               {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
+}
+
 class TestProducerListener : public BnProducerListener {
 public:
     sp<IGraphicBufferProducer> mIgbp;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 6af6195..2b6833e 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -34,19 +34,19 @@
 
 BlurFilter::BlurFilter() {
     SkString blurString(R"(
-        uniform shader input;
+        uniform shader child;
         uniform float2 in_blurOffset;
         uniform float2 in_maxSizeXY;
 
         half4 main(float2 xy) {
-            half4 c = input.eval(xy);
-            c += input.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+            half4 c = child.eval(xy);
+            c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
                                    clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-            c += input.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+            c += child.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
                                    clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-            c += input.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+            c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
                                    clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
-            c += input.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+            c += child.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
                                    clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
 
             return half4(c.rgb * 0.2, 1.0);
@@ -101,7 +101,7 @@
     // start by downscaling and doing the first blur pass
     SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
     SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
-    blurBuilder.child("input") =
+    blurBuilder.child("child") =
             input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
     blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
     blurBuilder.uniform("in_maxSizeXY") =
@@ -112,7 +112,7 @@
     // And now we'll build our chain of scaled blur stages
     for (auto i = 1; i < numberOfPasses; i++) {
         const float stepScale = (float)i * kInputScale;
-        blurBuilder.child("input") =
+        blurBuilder.child("child") =
                 tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
         blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
         blurBuilder.uniform("in_maxSizeXY") =
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index dc5fe17..73dadef 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -389,9 +389,9 @@
 
 static void generateEffectiveOOTF(bool undoPremultipliedAlpha, SkString& shader) {
     shader.append(R"(
-        uniform shader input;
+        uniform shader child;
         half4 main(float2 xy) {
-            float4 c = float4(input.eval(xy));
+            float4 c = float4(child.eval(xy));
     )");
     if (undoPremultipliedAlpha) {
         shader.append(R"(
@@ -451,7 +451,7 @@
     ATRACE_CALL();
     SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
 
-    effectBuilder.child("input") = shader;
+    effectBuilder.child("child") = shader;
 
     if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
         effectBuilder.uniform("in_rgbToXyz") = mat4();
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index c351676..db1a1cc 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -614,6 +614,8 @@
 
 Return<void> SensorDevice::onDynamicSensorsConnected(
         const hidl_vec<SensorInfo> &dynamicSensorsAdded) {
+    std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
+
     // Allocate a sensor_t structure for each dynamic sensor added and insert
     // it into the dictionary of connected dynamic sensors keyed by handle.
     for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
@@ -629,6 +631,8 @@
                 std::make_pair(sensor->handle, sensor));
     }
 
+    mDynamicSensorsCv.notify_all();
+
     return Return<void>();
 }
 
@@ -1174,8 +1178,20 @@
         dst->dynamic_sensor_meta.connected = dyn.connected;
         dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
         if (dyn.connected) {
+            std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
+            // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it
+            // can be received out of order from this event due to a bug in the HIDL spec that
+            // marks it as oneway.
             auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
-            CHECK(it != mConnectedDynamicSensors.end());
+            if (it == mConnectedDynamicSensors.end()) {
+                mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT,
+                        [&, dyn]{
+                            return mConnectedDynamicSensors.find(dyn.sensorHandle)
+                                    != mConnectedDynamicSensors.end();
+                });
+                it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+                CHECK(it != mConnectedDynamicSensors.end());
+            }
 
             dst->dynamic_sensor_meta.sensor = it->second;
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 75da7bb..bc8d20f 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -139,6 +139,14 @@
     Vector<sensor_t> mSensorList;
     std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
 
+    // A bug in the Sensors HIDL spec which marks onDynamicSensorsConnected as oneway causes dynamic
+    // meta events and onDynamicSensorsConnected to be received out of order. This mutex + CV are
+    // used to block meta event processing until onDynamicSensorsConnected is received to simplify
+    // HAL implementations.
+    std::mutex mDynamicSensorsMutex;
+    std::condition_variable mDynamicSensorsCv;
+    static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
+
     static const nsecs_t MINIMUM_EVENTS_PERIOD =   1000000; // 1000 Hz
     mutable Mutex mLock; // protect mActivationCount[].batchParams
     // fixed-size array after construction
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d805294..ef05fe2 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -620,14 +620,6 @@
     return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth;
 }
 
-uint64_t BufferLayer::getHeadFrameNumber(nsecs_t expectedPresentTime) const {
-    if (hasFrameUpdate()) {
-        return getFrameNumber(expectedPresentTime);
-    } else {
-        return mCurrentFrameNumber;
-    }
-}
-
 Rect BufferLayer::getBufferSize(const State& s) const {
     // If we have a sideband stream, or we are scaling the buffer then return the layer size since
     // we cannot determine the buffer size.
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 760c8b9..2da73f8 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -164,8 +164,6 @@
     void updateCloneBufferInfo() override;
     uint64_t mPreviousFrameNumber = 0;
 
-    uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const override;
-
     void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
 
     // Transform hint provided to the producer. This must be accessed holding
@@ -189,8 +187,6 @@
 private:
     virtual bool fenceHasSignaled() const = 0;
     virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
-    virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
-
 
     // Latch sideband stream and returns true if the dirty region should be updated.
     virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index d51db88..8bbe438 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -161,39 +161,6 @@
     return mQueueItems[0].item.mTimestamp <= expectedPresentTime;
 }
 
-uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
-    Mutex::Autolock lock(mQueueItemLock);
-    uint64_t frameNumber = mQueueItems[0].item.mFrameNumber;
-
-    // The head of the queue will be dropped if there are signaled and timely frames behind it
-    if (isRemovedFromCurrentState()) {
-        expectedPresentTime = 0;
-    }
-
-    for (size_t i = 1; i < mQueueItems.size(); i++) {
-        const bool fenceSignaled =
-                mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
-        if (!fenceSignaled) {
-            break;
-        }
-
-        // We don't drop frames without explicit timestamps
-        if (mQueueItems[i].item.mIsAutoTimestamp) {
-            break;
-        }
-
-        const nsecs_t desiredPresent = mQueueItems[i].item.mTimestamp;
-        if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
-            desiredPresent > expectedPresentTime) {
-            break;
-        }
-
-        frameNumber = mQueueItems[i].item.mFrameNumber;
-    }
-
-    return frameNumber;
-}
-
 bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
     // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
     editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index b3b7948..be2902b 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -89,7 +89,6 @@
     };
 
 private:
-    uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
 
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
     void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 7466c06..ed45cab 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -214,7 +214,7 @@
                 JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
     }
 
-    mFlinger->getTransactionCallbackInvoker().finalizePendingCallbackHandles(
+    mFlinger->getTransactionCallbackInvoker().addCallbackHandles(
             mDrawingState.callbackHandles, jankData);
 
     mDrawingState.callbackHandles = {};
@@ -406,15 +406,55 @@
     return true;
 }
 
-bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer,
-                                 const sp<Fence>& acquireFence, nsecs_t postTime,
+std::shared_ptr<renderengine::ExternalTexture> BufferStateLayer::getBufferFromBufferData(
+        const BufferData& bufferData) {
+    bool cacheIdChanged = bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged);
+    bool bufferSizeExceedsLimit = false;
+    std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
+    if (cacheIdChanged && bufferData.buffer != nullptr) {
+        bufferSizeExceedsLimit =
+                mFlinger->exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(),
+                                                     bufferData.buffer->getHeight());
+        if (!bufferSizeExceedsLimit) {
+            ClientCache::getInstance().add(bufferData.cachedBuffer, bufferData.buffer);
+            buffer = ClientCache::getInstance().get(bufferData.cachedBuffer);
+        }
+    } else if (cacheIdChanged) {
+        buffer = ClientCache::getInstance().get(bufferData.cachedBuffer);
+    } else if (bufferData.buffer != nullptr) {
+        bufferSizeExceedsLimit =
+                mFlinger->exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(),
+                                                     bufferData.buffer->getHeight());
+        if (!bufferSizeExceedsLimit) {
+            buffer = std::make_shared<
+                    renderengine::ExternalTexture>(bufferData.buffer, mFlinger->getRenderEngine(),
+                                                   renderengine::ExternalTexture::Usage::READABLE);
+        }
+    }
+    ALOGE_IF(bufferSizeExceedsLimit,
+             "Attempted to create an ExternalTexture for layer %s that exceeds render target size "
+             "limit.",
+             getDebugName());
+    return buffer;
+}
+
+bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime,
                                  nsecs_t desiredPresentTime, bool isAutoTimestamp,
-                                 const client_cache_t& clientCacheId, uint64_t frameNumber,
-                                 std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
-                                 const sp<ITransactionCompletedListener>& releaseBufferListener,
-                                 const sp<IBinder>& releaseBufferEndpoint) {
+                                 std::optional<nsecs_t> dequeueTime,
+                                 const FrameTimelineInfo& info) {
     ATRACE_CALL();
 
+    const std::shared_ptr<renderengine::ExternalTexture>& buffer =
+            getBufferFromBufferData(bufferData);
+    if (!buffer) {
+        return false;
+    }
+
+    const bool frameNumberChanged =
+            bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged);
+    const uint64_t frameNumber =
+            frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1;
+
     if (mDrawingState.buffer) {
         mReleasePreviousBuffer = true;
         if (mDrawingState.buffer != mBufferInfo.mBuffer ||
@@ -438,9 +478,17 @@
     }
 
     mDrawingState.frameNumber = frameNumber;
-    mDrawingState.releaseBufferListener = releaseBufferListener;
+    mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
     mDrawingState.buffer = buffer;
-    mDrawingState.clientCacheId = clientCacheId;
+    mDrawingState.clientCacheId = bufferData.cachedBuffer;
+
+    mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
+            ? bufferData.acquireFence
+            : Fence::NO_FENCE;
+    mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence);
+    // The acquire fences of BufferStateLayers have already signaled before they are set
+    mCallbackHandleAcquireTime = mDrawingState.acquireFenceTime->getSignalTime();
+
     mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
 
@@ -462,7 +510,7 @@
     mFlinger->mScheduler->recordLayerHistory(this, presentTime,
                                              LayerHistory::LayerUpdateType::Buffer);
 
-    addFrameEvent(acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
+    addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
 
     setFrameTimelineVsyncForBufferTransaction(info, postTime);
 
@@ -477,20 +525,7 @@
 
     mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth();
     mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight();
-    mDrawingState.releaseBufferEndpoint = releaseBufferEndpoint;
-
-    return true;
-}
-
-bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
-    mDrawingState.acquireFence = fence;
-    mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(fence);
-
-    // The acquire fences of BufferStateLayers have already signaled before they are set
-    mCallbackHandleAcquireTime = mDrawingState.acquireFenceTime->getSignalTime();
-
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
+    mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint;
     return true;
 }
 
@@ -564,10 +599,6 @@
             handle->acquireTime = mCallbackHandleAcquireTime;
             handle->frameNumber = mDrawingState.frameNumber;
 
-            // Notify the transaction completed thread that there is a pending latched callback
-            // handle
-            mFlinger->getTransactionCallbackInvoker().registerPendingCallbackHandle(handle);
-
             // Store so latched time and release fence can be set
             mDrawingState.callbackHandles.push_back(handle);
 
@@ -659,36 +690,6 @@
     return BufferLayer::onPreComposition(refreshStartTime);
 }
 
-uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
-    return mDrawingState.frameNumber;
-}
-
-/**
- * This is the frameNumber used for deferred transaction signalling. We need to use this because
- * of cases where we defer a transaction for a surface to itself. In the BLAST world this
- * may not make a huge amount of sense (Why not just merge the Buffer transaction with the
- * deferred transaction?) but this is an important legacy use case, for example moving
- * a window at the same time it draws makes use of this kind of technique. So anyway
- * imagine we have something like this:
- *
- * Transaction { // containing
- *     Buffer -> frameNumber = 2
- *     DeferTransactionUntil -> frameNumber = 2
- *     Random other stuff
- *  }
- * Now imagine mFrameNumber returned mDrawingState.frameNumber (or mCurrentFrameNumber).
- * Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we
- * haven't swapped mDrawingState to mDrawingState yet we will think the sync point
- * is not ready. So we will return false from applyPendingState and not swap
- * current state to drawing state. But because we don't swap current state
- * to drawing state the number will never update and we will be stuck. This way
- * we can see we need to return the frame number for the buffer we are about
- * to apply.
- */
-uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const {
-    return mDrawingState.frameNumber;
-}
-
 void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
     if (!mAutoRefresh.exchange(autoRefresh)) {
         mFlinger->signalLayerUpdate();
@@ -765,7 +766,7 @@
 
     std::deque<sp<CallbackHandle>> remainingHandles;
     mFlinger->getTransactionCallbackInvoker()
-            .finalizeOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
+            .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
     mDrawingState.callbackHandles = remainingHandles;
 
     mDrawingStateModified = false;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 124e91a..87b68ea 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -55,13 +55,9 @@
     bool setTransform(uint32_t transform) override;
     bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
     bool setCrop(const Rect& crop) override;
-    bool setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& buffer,
-                   const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime,
-                   bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber,
-                   std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
-                   const sp<ITransactionCompletedListener>& transactionListener,
-                   const sp<IBinder>& releaseBufferEndpoint) override;
-    bool setAcquireFence(const sp<Fence>& fence) override;
+    bool setBuffer(const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
+                   bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
+                   const FrameTimelineInfo& info) override;
     bool setDataspace(ui::Dataspace dataspace) override;
     bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
     bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
@@ -105,7 +101,6 @@
 
 protected:
     void gatherBufferInfo() override;
-    uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
     void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
     ui::Transform getInputTransform() const override;
     Rect getInputBounds() const override;
@@ -122,8 +117,6 @@
 
     status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
 
-    uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
-
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
 
     bool hasFrameUpdate() const override;
@@ -143,6 +136,9 @@
 
     bool bufferNeedsFiltering() const override;
 
+    std::shared_ptr<renderengine::ExternalTexture> getBufferFromBufferData(
+            const BufferData& bufferData);
+
     sp<Fence> mPreviousReleaseFence;
     ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
     uint64_t mPreviousReleasedFrameNumber = 0;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8c281d5..f29ebde 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -416,17 +416,11 @@
     // Used only to set BufferStateLayer state
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
     virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
-    virtual bool setBuffer(const std::shared_ptr<renderengine::ExternalTexture>& /*buffer*/,
-                           const sp<Fence>& /*acquireFence*/, nsecs_t /*postTime*/,
-                           nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
-                           const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */,
-                           std::optional<nsecs_t> /* dequeueTime */,
-                           const FrameTimelineInfo& /*info*/,
-                           const sp<ITransactionCompletedListener>& /* releaseBufferListener */,
-                           const sp<IBinder>& /* releaseBufferEndpoint */) {
+    virtual bool setBuffer(const BufferData&, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
+                           bool /*isAutoTimestamp*/, std::optional<nsecs_t> /* dequeueTime */,
+                           const FrameTimelineInfo& /*info*/) {
         return false;
     };
-    virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
     virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
     virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
     virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
@@ -527,8 +521,6 @@
 
     virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
 
-    virtual uint64_t getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const { return 0; }
-
     /*
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3f6bd6f..c9f00a0 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -22,6 +22,7 @@
 #pragma clang diagnostic ignored "-Wextra"
 
 #include "RefreshRateConfigs.h"
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <utils/Trace.h>
 #include <chrono>
@@ -714,9 +715,31 @@
 RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
                                        Config config)
       : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
+    initializeIdleTimer();
     updateDisplayModes(modes, currentModeId);
 }
 
+void RefreshRateConfigs::initializeIdleTimer() {
+    if (mConfig.idleTimerTimeoutMs > 0) {
+        const auto getCallback = [this]() -> std::optional<IdleTimerCallbacks::Callbacks> {
+            std::scoped_lock lock(mIdleTimerCallbacksMutex);
+            if (!mIdleTimerCallbacks.has_value()) return {};
+            return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel
+                                                  : mIdleTimerCallbacks->platform;
+        };
+
+        mIdleTimer.emplace(
+                "IdleTimer", std::chrono::milliseconds(mConfig.idleTimerTimeoutMs),
+                [getCallback] {
+                    if (const auto callback = getCallback()) callback->onReset();
+                },
+                [getCallback] {
+                    if (const auto callback = getCallback()) callback->onExpired();
+                });
+        mIdleTimer->start();
+    }
+}
+
 void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
                                             DisplayModeId currentModeId) {
     std::lock_guard lock(mLock);
@@ -990,6 +1013,9 @@
 
     base::StringAppendF(&result, "Supports Frame Rate Override: %s\n",
                         mSupportsFrameRateOverride ? "yes" : "no");
+    base::StringAppendF(&result, "Idle timer: (%s) %s\n",
+                        mConfig.supportKernelIdleTimer ? "kernel" : "platform",
+                        mIdleTimer ? mIdleTimer->dump().c_str() : "off");
     result.append("\n");
 }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index ffaa029..3abf83d 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -27,6 +27,7 @@
 #include "DisplayHardware/DisplayMode.h"
 #include "DisplayHardware/HWComposer.h"
 #include "Fps.h"
+#include "Scheduler/OneShotTimer.h"
 #include "Scheduler/SchedulerUtils.h"
 #include "Scheduler/Seamlessness.h"
 #include "Scheduler/StrongTyping.h"
@@ -305,11 +306,19 @@
         // or heuristic, such that refresh rates higher than this value will not be voted for. 0 if
         // no threshold is set.
         int frameRateMultipleThreshold = 0;
+
+        // The Idle Timer timeout. 0 timeout means no idle timer.
+        int32_t idleTimerTimeoutMs = 0;
+
+        // Whether to use idle timer callbacks that support the kernel timer.
+        bool supportKernelIdleTimer = false;
     };
 
-    RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
+    RefreshRateConfigs(const DisplayModes&, DisplayModeId,
                        Config config = {.enableFrameRateOverride = false,
-                                        .frameRateMultipleThreshold = 0});
+                                        .frameRateMultipleThreshold = 0,
+                                        .idleTimerTimeoutMs = 0,
+                                        .supportKernelIdleTimer = false});
 
     // Returns whether switching modes (refresh rate or resolution) is possible.
     // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only
@@ -349,6 +358,30 @@
                                                  Fps displayFrameRate, bool touch) const
             EXCLUDES(mLock);
 
+    bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }
+
+    void setIdleTimerCallbacks(std::function<void()> platformTimerReset,
+                               std::function<void()> platformTimerExpired,
+                               std::function<void()> kernelTimerReset,
+                               std::function<void()> kernelTimerExpired) {
+        std::scoped_lock lock(mIdleTimerCallbacksMutex);
+        mIdleTimerCallbacks.emplace();
+        mIdleTimerCallbacks->platform.onReset = platformTimerReset;
+        mIdleTimerCallbacks->platform.onExpired = platformTimerExpired;
+        mIdleTimerCallbacks->kernel.onReset = kernelTimerReset;
+        mIdleTimerCallbacks->kernel.onExpired = kernelTimerExpired;
+    }
+
+    void resetIdleTimer(bool kernelOnly) {
+        if (!mIdleTimer) {
+            return;
+        }
+        if (kernelOnly && !mConfig.supportKernelIdleTimer) {
+            return;
+        }
+        mIdleTimer->reset();
+    };
+
     void dump(std::string& result) const EXCLUDES(mLock);
 
     RefreshRateConfigs(const RefreshRateConfigs&) = delete;
@@ -414,6 +447,8 @@
 
     void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
 
+    void initializeIdleTimer();
+
     // The list of refresh rates, indexed by display modes ID. This may change after this
     // object is initialized.
     AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
@@ -457,6 +492,22 @@
     };
     mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
             GUARDED_BY(mLock);
+
+    // Timer that records time between requests for next vsync.
+    std::optional<scheduler::OneShotTimer> mIdleTimer;
+
+    struct IdleTimerCallbacks {
+        struct Callbacks {
+            std::function<void()> onReset;
+            std::function<void()> onExpired;
+        };
+
+        Callbacks platform;
+        Callbacks kernel;
+    };
+
+    std::mutex mIdleTimerCallbacksMutex;
+    std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex);
 };
 
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c64ccd1..12e741b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -120,28 +120,15 @@
 Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
                      ISchedulerCallback& callback)
       : Scheduler(configs, callback,
-                  {.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
-                   .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
+                  {.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
 }
 
 Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
                      ISchedulerCallback& callback, Options options)
-      : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback,
+      : Scheduler(createVsyncSchedule(configs->supportsKernelIdleTimer()), configs, callback,
                   createLayerHistory(), options) {
     using namespace sysprop;
 
-    const int setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0);
-
-    if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
-        const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback
-                                                          : &Scheduler::idleTimerCallback;
-        mIdleTimer.emplace(
-                "IdleTimer", std::chrono::milliseconds(millis),
-                [this, callback] { std::invoke(callback, this, TimerState::Reset); },
-                [this, callback] { std::invoke(callback, this, TimerState::Expired); });
-        mIdleTimer->start();
-    }
-
     if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
         // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
         mTouchTimer.emplace(
@@ -168,11 +155,11 @@
         mVsyncSchedule(std::move(schedule)),
         mLayerHistory(std::move(layerHistory)),
         mSchedulerCallback(schedulerCallback),
-        mRefreshRateConfigs(configs),
         mPredictedVsyncTracer(
                 base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
                         ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
                         : nullptr) {
+    setRefreshRateConfigs(configs);
     mSchedulerCallback.setVsyncEnabled(false);
 }
 
@@ -180,7 +167,7 @@
     // Ensure the OneShotTimer threads are joined before we start destroying state.
     mDisplayPowerTimer.reset();
     mTouchTimer.reset();
-    mIdleTimer.reset();
+    mRefreshRateConfigs.reset();
 }
 
 Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) {
@@ -672,18 +659,16 @@
 }
 
 void Scheduler::resetIdleTimer() {
-    if (mIdleTimer) {
-        mIdleTimer->reset();
-    }
+    std::scoped_lock lock(mRefreshRateConfigsLock);
+    mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ false);
 }
 
 void Scheduler::onTouchHint() {
     if (mTouchTimer) {
         mTouchTimer->reset();
 
-        if (mOptions.supportKernelTimer && mIdleTimer) {
-            mIdleTimer->reset();
-        }
+        std::scoped_lock lock(mRefreshRateConfigsLock);
+        mRefreshRateConfigs->resetIdleTimer(/*kernelOnly*/ true);
     }
 }
 
@@ -755,7 +740,6 @@
 void Scheduler::dump(std::string& result) const {
     using base::StringAppendF;
 
-    StringAppendF(&result, "+  Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off");
     StringAppendF(&result, "+  Touch timer: %s\n",
                   mTouchTimer ? mTouchTimer->dump().c_str() : "off");
     StringAppendF(&result, "+  Content detection: %s %s\n\n",
@@ -867,7 +851,7 @@
     }
 
     const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
-    const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;
+    const bool idle = mFeatures.idleTimer == TimerState::Expired;
 
     return refreshRateConfigs
             ->getBestRefreshRate(mFeatures.contentRequirements,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 420ba61..3f3debe 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -136,7 +136,6 @@
     // Detects content using layer history, and selects a matching refresh rate.
     void chooseRefreshRateForContent() EXCLUDES(mRefreshRateConfigsLock);
 
-    bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
     void resetIdleTimer();
 
     // Indicates that touch interaction is taking place.
@@ -187,6 +186,15 @@
             EXCLUDES(mRefreshRateConfigsLock) {
         std::scoped_lock lock(mRefreshRateConfigsLock);
         mRefreshRateConfigs = std::move(refreshRateConfigs);
+        mRefreshRateConfigs->setIdleTimerCallbacks(
+                [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); },
+                [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired); },
+                [this] {
+                    std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset);
+                },
+                [this] {
+                    std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired);
+                });
     }
 
     nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
@@ -206,8 +214,6 @@
     enum class TouchState { Inactive, Active };
 
     struct Options {
-        // Whether to use idle timer callbacks that support the kernel timer.
-        bool supportKernelTimer;
         // Whether to use content detection at all.
         bool useContentDetection;
     };
@@ -293,8 +299,6 @@
     // Used to choose refresh rate if content detection is enabled.
     std::unique_ptr<LayerHistory> mLayerHistory;
 
-    // Timer that records time between requests for next vsync.
-    std::optional<scheduler::OneShotTimer> mIdleTimer;
     // Timer used to monitor touch events.
     std::optional<scheduler::OneShotTimer> mTouchTimer;
     // Timer used to monitor display power mode.
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 7b5d462..ee973f7 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -42,6 +42,7 @@
       : mClock(std::move(clock)),
         mTracker(tracker),
         mPendingLimit(pendingFenceLimit),
+        // TODO(adyabr): change mSupportKernelIdleTimer when the active display changes
         mSupportKernelIdleTimer(supportKernelIdleTimer) {}
 
 VSyncReactor::~VSyncReactor() = default;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4345b84..e90af3a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -277,6 +277,40 @@
     ROTATE_SURFACE_FLINGER = 0x2,
 };
 
+struct IdleTimerConfig {
+    int32_t timeoutMs;
+    bool supportKernelIdleTimer;
+};
+
+IdleTimerConfig getIdleTimerConfiguration(DisplayId displayId) {
+    // TODO(adyabr): use ro.surface_flinger.* namespace
+
+    const auto displayIdleTimerMsKey = [displayId] {
+        std::stringstream ss;
+        ss << "debug.sf.set_idle_timer_ms_" << displayId.value;
+        return ss.str();
+    }();
+
+    const auto displaySupportKernelIdleTimerKey = [displayId] {
+        std::stringstream ss;
+        ss << "debug.sf.support_kernel_idle_timer_" << displayId.value;
+        return ss.str();
+    }();
+
+    const int32_t displayIdleTimerMs = base::GetIntProperty(displayIdleTimerMsKey, 0);
+    const auto displaySupportKernelIdleTimer =
+            base::GetBoolProperty(displaySupportKernelIdleTimerKey, false);
+
+    if (displayIdleTimerMs > 0) {
+        return {displayIdleTimerMs, displaySupportKernelIdleTimer};
+    }
+
+    const int32_t setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms", 0);
+    const int32_t millis = setIdleTimerMs ? setIdleTimerMs : sysprop::set_idle_timer_ms(0);
+
+    return {millis, sysprop::support_kernel_idle_timer(false)};
+}
+
 }  // namespace anonymous
 
 // ---------------------------------------------------------------------------
@@ -462,9 +496,6 @@
 
     useFrameRateApi = use_frame_rate_api(true);
 
-    mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false);
-    base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false");
-
     mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
 
     // Debug property overrides ro. property
@@ -2152,10 +2183,11 @@
 
 bool SurfaceFlinger::handleMessageInvalidate() {
     ATRACE_CALL();
+        // Send on commit callbacks
+    mTransactionCallbackInvoker.sendCallbacks();
+
     bool refreshNeeded = handlePageFlip();
 
-    // Send on commit callbacks
-    mTransactionCallbackInvoker.sendCallbacks();
 
     if (mVisibleRegionsDirty) {
         computeLayerBounds();
@@ -2346,6 +2378,7 @@
 
     mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
     mTransactionCallbackInvoker.sendCallbacks();
+    mTransactionCallbackInvoker.clearCompletedTransactions();
 
     if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
         mPreviousPresentFences[0].fenceTime->isValid()) {
@@ -2653,10 +2686,14 @@
         creationArgs.connectionType = physical->type;
         creationArgs.supportedModes = physical->supportedModes;
         creationArgs.activeModeId = physical->activeMode->getId();
+        const auto [idleTimerTimeoutMs, supportKernelIdleTimer] =
+                getIdleTimerConfiguration(compositionDisplay->getId());
         scheduler::RefreshRateConfigs::Config config =
                 {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
                  .frameRateMultipleThreshold =
-                         base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)};
+                         base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0),
+                 .idleTimerTimeoutMs = idleTimerTimeoutMs,
+                 .supportKernelIdleTimer = supportKernelIdleTimer};
         creationArgs.refreshRateConfigs =
                 std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes,
                                                                 creationArgs.activeModeId, config);
@@ -3564,9 +3601,10 @@
 
     for (const ComposerState& state : states) {
         const layer_state_t& s = state.state;
-        const bool acquireFenceChanged = (s.what & layer_state_t::eAcquireFenceChanged);
-        if (acquireFenceChanged && s.acquireFence && !enableLatchUnsignaled &&
-            s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+        const bool acquireFenceChanged =
+                s.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged);
+        if (acquireFenceChanged && s.bufferData.acquireFence && !enableLatchUnsignaled &&
+            s.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) {
             ATRACE_NAME("fence unsignaled");
             return false;
         }
@@ -3729,8 +3767,7 @@
     // that listeners with SurfaceControls will start registration during setClientStateLocked
     // below.
     for (const auto& listener : listenerCallbacks) {
-        mTransactionCallbackInvoker.startRegistration(listener);
-        mTransactionCallbackInvoker.endRegistration(listener);
+        mTransactionCallbackInvoker.addEmptyTransaction(listener);
     }
 
     std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
@@ -3748,10 +3785,6 @@
         }
     }
 
-    for (const auto& listenerCallback : listenerCallbacksWithSurfaces) {
-        mTransactionCallbackInvoker.endRegistration(listenerCallback);
-    }
-
     // If the state doesn't require a traversal and there are callbacks, send them now
     if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) {
         mTransactionCallbackInvoker.sendCallbacks();
@@ -3881,14 +3914,12 @@
 
         ListenerCallbacks onCommitCallbacks = listener.filter(CallbackId::Type::ON_COMMIT);
         if (!onCommitCallbacks.callbackIds.empty()) {
-            mTransactionCallbackInvoker.startRegistration(onCommitCallbacks);
             filteredListeners.push_back(onCommitCallbacks);
             outListenerCallbacks.insert(onCommitCallbacks);
         }
 
         ListenerCallbacks onCompleteCallbacks = listener.filter(CallbackId::Type::ON_COMPLETE);
         if (!onCompleteCallbacks.callbackIds.empty()) {
-            mTransactionCallbackInvoker.startRegistration(onCompleteCallbacks);
             filteredListeners.push_back(onCompleteCallbacks);
             outListenerCallbacks.insert(onCompleteCallbacks);
         }
@@ -4063,9 +4094,6 @@
     if (what & layer_state_t::eCropChanged) {
         if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
     }
-    if (what & layer_state_t::eAcquireFenceChanged) {
-        if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
-    }
     if (what & layer_state_t::eDataspaceChanged) {
         if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded;
     }
@@ -4192,43 +4220,11 @@
             callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
         }
     }
-    bool bufferChanged = what & layer_state_t::eBufferChanged;
-    bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
-    bool bufferSizeExceedsLimit = false;
-    std::shared_ptr<renderengine::ExternalTexture> buffer;
-    if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
-        bufferSizeExceedsLimit =
-                exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight());
-        if (!bufferSizeExceedsLimit) {
-            ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
-            buffer = ClientCache::getInstance().get(s.cachedBuffer);
-        }
-    } else if (cacheIdChanged) {
-        buffer = ClientCache::getInstance().get(s.cachedBuffer);
-    } else if (bufferChanged && s.buffer != nullptr) {
-        bufferSizeExceedsLimit =
-                exceedsMaxRenderTargetSize(s.buffer->getWidth(), s.buffer->getHeight());
-        if (!bufferSizeExceedsLimit) {
-            buffer = std::make_shared<
-                    renderengine::ExternalTexture>(s.buffer, getRenderEngine(),
-                                                   renderengine::ExternalTexture::Usage::READABLE);
-        }
-    }
-    ALOGE_IF(bufferSizeExceedsLimit,
-             "Attempted to create an ExternalTexture for layer %s that exceeds render target size "
-             "limit.",
-             layer->getDebugName());
-    if (buffer) {
-        const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged;
-        const uint64_t frameNumber = frameNumberChanged
-                ? s.frameNumber
-                : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1;
 
-        if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
-                             s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo,
-                             s.releaseBufferListener, s.releaseBufferEndpoint)) {
-            flags |= eTraversalNeeded;
-        }
+    if (what & layer_state_t::eBufferChanged &&
+        layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,
+                         dequeueBufferTimestamp, frameTimelineInfo)) {
+        flags |= eTraversalNeeded;
     } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
         layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime);
     }
@@ -5846,16 +5842,18 @@
 void SurfaceFlinger::toggleKernelIdleTimer() {
     using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
 
-    // If the support for kernel idle timer is disabled in SF code, don't do anything.
-    if (!mSupportKernelIdleTimer) {
-        return;
-    }
     const auto display = getDefaultDisplayDeviceLocked();
     if (!display) {
         ALOGW("%s: default display is null", __func__);
         return;
     }
 
+    // If the support for kernel idle timer is disabled for the active display,
+    // don't do anything.
+    if (!display->refreshRateConfigs().supportsKernelIdleTimer()) {
+        return;
+    }
+
     const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction();
     switch (action) {
         case KernelIdleTimerAction::TurnOff:
@@ -6978,6 +6976,10 @@
     mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs());
     onActiveDisplaySizeChanged(activeDisplay);
     mActiveDisplayTransformHint = activeDisplay->getTransformHint();
+
+    // Update the kernel timer for the current active display, since the policy
+    // for this display might have changed when it was not the active display.
+    toggleKernelIdleTimer();
 }
 
 status_t SurfaceFlinger::addWindowInfosListener(
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6c046fc..1217d63 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -363,6 +363,10 @@
         return static_cast<bool>(findDisplay(p));
     }
 
+    bool exceedsMaxRenderTargetSize(uint32_t width, uint32_t height) const {
+        return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize;
+    }
+
 private:
     friend class BufferLayer;
     friend class BufferQueueLayer;
@@ -759,8 +763,6 @@
     // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
     // make calls to sys prop each time.
     bool mKernelIdleTimerEnabled = false;
-    // Keeps track of whether the kernel timer is supported on the SF side.
-    bool mSupportKernelIdleTimer = false;
     // Show spinner with refresh rate overlay
     bool mRefreshRateOverlaySpinner = false;
 
@@ -939,10 +941,6 @@
 
     void readPersistentProperties();
 
-    bool exceedsMaxRenderTargetSize(uint32_t width, uint32_t height) const {
-        return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize;
-    }
-
     uint32_t getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
 
     /*
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 6af69f0..4b12a26 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -49,121 +49,25 @@
     return !callbacks.empty() && callbacks.front().type == CallbackId::Type::ON_COMMIT;
 }
 
-TransactionCallbackInvoker::~TransactionCallbackInvoker() {
-    {
-        std::lock_guard lock(mMutex);
-        for (const auto& [listener, transactionStats] : mCompletedTransactions) {
-            listener->unlinkToDeath(mDeathRecipient);
-        }
-    }
-}
-
-status_t TransactionCallbackInvoker::startRegistration(const ListenerCallbacks& listenerCallbacks) {
-    std::lock_guard lock(mMutex);
-
-    auto [itr, inserted] = mRegisteringTransactions.insert(listenerCallbacks);
+void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) {
     auto& [listener, callbackIds] = listenerCallbacks;
-
-    if (inserted) {
-        if (mCompletedTransactions.count(listener) == 0) {
-            status_t err = listener->linkToDeath(mDeathRecipient);
-            if (err != NO_ERROR) {
-                ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
-                return err;
-            }
-        }
-        auto& transactionStatsDeque = mCompletedTransactions[listener];
-        transactionStatsDeque.emplace_back(callbackIds);
-    }
-
-    return NO_ERROR;
+    auto& transactionStatsDeque = mCompletedTransactions[listener];
+    transactionStatsDeque.emplace_back(callbackIds);
 }
 
-status_t TransactionCallbackInvoker::endRegistration(const ListenerCallbacks& listenerCallbacks) {
-    std::lock_guard lock(mMutex);
-
-    auto itr = mRegisteringTransactions.find(listenerCallbacks);
-    if (itr == mRegisteringTransactions.end()) {
-        ALOGE("cannot end a registration that does not exist");
-        return BAD_VALUE;
-    }
-
-    mRegisteringTransactions.erase(itr);
-
-    return NO_ERROR;
-}
-
-bool TransactionCallbackInvoker::isRegisteringTransaction(
-        const sp<IBinder>& transactionListener, const std::vector<CallbackId>& callbackIds) {
-    ListenerCallbacks listenerCallbacks(transactionListener, callbackIds);
-
-    auto itr = mRegisteringTransactions.find(listenerCallbacks);
-    return itr != mRegisteringTransactions.end();
-}
-
-status_t TransactionCallbackInvoker::registerPendingCallbackHandle(
-        const sp<CallbackHandle>& handle) {
-    std::lock_guard lock(mMutex);
-
-    // If we can't find the transaction stats something has gone wrong. The client should call
-    // startRegistration before trying to register a pending callback handle.
-    TransactionStats* transactionStats;
-    status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
-    if (err != NO_ERROR) {
-        ALOGE("cannot find transaction stats");
-        return err;
-    }
-
-    mPendingTransactions[handle->listener][handle->callbackIds]++;
-    return NO_ERROR;
-}
-
-status_t TransactionCallbackInvoker::finalizeCallbackHandle(const sp<CallbackHandle>& handle,
-                                                            const std::vector<JankData>& jankData) {
-    auto listener = mPendingTransactions.find(handle->listener);
-    if (listener != mPendingTransactions.end()) {
-        auto& pendingCallbacks = listener->second;
-        auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
-
-        if (pendingCallback != pendingCallbacks.end()) {
-            auto& pendingCount = pendingCallback->second;
-
-            // Decrease the pending count for this listener
-            if (--pendingCount == 0) {
-                pendingCallbacks.erase(pendingCallback);
-            }
-        } else {
-            ALOGW("there are more latched callbacks than there were registered callbacks");
-        }
-        if (listener->second.size() == 0) {
-            mPendingTransactions.erase(listener);
-        }
-    } else {
-        ALOGW("cannot find listener in mPendingTransactions");
-    }
-
-    status_t err = addCallbackHandle(handle, jankData);
-    if (err != NO_ERROR) {
-        ALOGE("could not add callback handle");
-        return err;
-    }
-    return NO_ERROR;
-}
-
-status_t TransactionCallbackInvoker::finalizeOnCommitCallbackHandles(
+status_t TransactionCallbackInvoker::addOnCommitCallbackHandles(
         const std::deque<sp<CallbackHandle>>& handles,
         std::deque<sp<CallbackHandle>>& outRemainingHandles) {
     if (handles.empty()) {
         return NO_ERROR;
     }
-    std::lock_guard lock(mMutex);
     const std::vector<JankData>& jankData = std::vector<JankData>();
     for (const auto& handle : handles) {
         if (!containsOnCommitCallbacks(handle->callbackIds)) {
             outRemainingHandles.push_back(handle);
             continue;
         }
-        status_t err = finalizeCallbackHandle(handle, jankData);
+        status_t err = addCallbackHandle(handle, jankData);
         if (err != NO_ERROR) {
             return err;
         }
@@ -172,14 +76,13 @@
     return NO_ERROR;
 }
 
-status_t TransactionCallbackInvoker::finalizePendingCallbackHandles(
+status_t TransactionCallbackInvoker::addCallbackHandles(
         const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
     if (handles.empty()) {
         return NO_ERROR;
     }
-    std::lock_guard lock(mMutex);
     for (const auto& handle : handles) {
-        status_t err = finalizeCallbackHandle(handle, jankData);
+        status_t err = addCallbackHandle(handle, jankData);
         if (err != NO_ERROR) {
             return err;
         }
@@ -190,8 +93,6 @@
 
 status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle(
         const sp<CallbackHandle>& handle) {
-    std::lock_guard lock(mMutex);
-
     return addCallbackHandle(handle, std::vector<JankData>());
 }
 
@@ -208,9 +109,8 @@
             return NO_ERROR;
         }
     }
-
-    ALOGE("could not find transaction stats");
-    return BAD_VALUE;
+    *outTransactionStats = &transactionStatsDeque.emplace_back(callbackIds);
+    return NO_ERROR;
 }
 
 status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& handle,
@@ -244,13 +144,10 @@
 }
 
 void TransactionCallbackInvoker::addPresentFence(const sp<Fence>& presentFence) {
-    std::lock_guard<std::mutex> lock(mMutex);
     mPresentFence = presentFence;
 }
 
 void TransactionCallbackInvoker::sendCallbacks() {
-    std::lock_guard lock(mMutex);
-
     // For each listener
     auto completedTransactionsItr = mCompletedTransactions.begin();
     while (completedTransactionsItr != mCompletedTransactions.end()) {
@@ -263,27 +160,9 @@
         while (transactionStatsItr != transactionStatsDeque.end()) {
             auto& transactionStats = *transactionStatsItr;
 
-            // If this transaction is still registering, it is not safe to send a callback
-            // because there could be surface controls that haven't been added to
-            // transaction stats or mPendingTransactions.
-            if (isRegisteringTransaction(listener, transactionStats.callbackIds)) {
-                break;
-            }
-
-            // If we are still waiting on the callback handles for this transaction, stop
-            // here because all transaction callbacks for the same listener must come in order
-            auto pendingTransactions = mPendingTransactions.find(listener);
-            if (pendingTransactions != mPendingTransactions.end() &&
-                pendingTransactions->second.count(transactionStats.callbackIds) != 0) {
-                break;
-            }
-
             // If the transaction has been latched
             if (transactionStats.latchTime >= 0 &&
                 !containsOnCommitCallbacks(transactionStats.callbackIds)) {
-                if (!mPresentFence) {
-                    break;
-                }
                 transactionStats.presentFence = mPresentFence;
             }
 
@@ -303,20 +182,9 @@
                 // we get pointers that compare unequal in the SF process.
                 interface_cast<ITransactionCompletedListener>(listenerStats.listener)
                         ->onTransactionCompleted(listenerStats);
-                if (transactionStatsDeque.empty()) {
-                    listener->unlinkToDeath(mDeathRecipient);
-                    completedTransactionsItr =
-                            mCompletedTransactions.erase(completedTransactionsItr);
-                } else {
-                    completedTransactionsItr++;
-                }
-            } else {
-                completedTransactionsItr =
-                        mCompletedTransactions.erase(completedTransactionsItr);
             }
-        } else {
-            completedTransactionsItr++;
         }
+        completedTransactionsItr++;
     }
 
     if (mPresentFence) {
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 6f4d812..71ca6e5 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -56,79 +56,38 @@
 
 class TransactionCallbackInvoker {
 public:
-    ~TransactionCallbackInvoker();
-
-    // Adds listener and callbackIds in case there are no SurfaceControls that are supposed
-    // to be included in the callback. This functions should be call before attempting to register
-    // any callback handles.
-    status_t startRegistration(const ListenerCallbacks& listenerCallbacks);
-    // Ends the registration. After this is called, no more CallbackHandles will be registered.
-    // It is safe to send a callback if the Transaction doesn't have any Pending callback handles.
-    status_t endRegistration(const ListenerCallbacks& listenerCallbacks);
-
-    // Informs the TransactionCallbackInvoker that there is a Transaction with a CallbackHandle
-    // that needs to be latched and presented this frame. This function should be called once the
-    // layer has received the CallbackHandle so the TransactionCallbackInvoker knows not to send
-    // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
-    // presented.
-    status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
-    // Notifies the TransactionCallbackInvoker that a pending CallbackHandle has been presented.
-    status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+    status_t addCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                             const std::vector<JankData>& jankData);
-    status_t finalizeOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+    status_t addOnCommitCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                              std::deque<sp<CallbackHandle>>& outRemainingHandles);
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
     status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
+    void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks);
 
     void addPresentFence(const sp<Fence>& presentFence);
 
     void sendCallbacks();
-
-private:
-
-    bool isRegisteringTransaction(const sp<IBinder>& transactionListener,
-                                  const std::vector<CallbackId>& callbackIds) REQUIRES(mMutex);
-
-    status_t findTransactionStats(const sp<IBinder>& listener,
-                                  const std::vector<CallbackId>& callbackIds,
-                                  TransactionStats** outTransactionStats) REQUIRES(mMutex);
+    void clearCompletedTransactions() {
+        mCompletedTransactions.clear();
+    }
 
     status_t addCallbackHandle(const sp<CallbackHandle>& handle,
-                               const std::vector<JankData>& jankData) REQUIRES(mMutex);
+                               const std::vector<JankData>& jankData);
 
-    status_t finalizeCallbackHandle(const sp<CallbackHandle>& handle,
-                                    const std::vector<JankData>& jankData) REQUIRES(mMutex);
 
-    class CallbackDeathRecipient : public IBinder::DeathRecipient {
-    public:
-        // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
-        // Death recipients needs a binderDied function.
-        //
-        // (isBinderAlive checks if BpBinder's mAlive is 0. mAlive is only set to 0 in sendObituary.
-        // sendObituary is only called if linkToDeath was called with a DeathRecipient.)
-        void binderDied(const wp<IBinder>& /*who*/) override {}
-    };
-    sp<CallbackDeathRecipient> mDeathRecipient =
-        new CallbackDeathRecipient();
+private:
+    status_t findTransactionStats(const sp<IBinder>& listener,
+                                  const std::vector<CallbackId>& callbackIds,
+                                  TransactionStats** outTransactionStats);
 
-    std::mutex mMutex;
-    std::condition_variable_any mConditionVariable;
 
-    std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> mRegisteringTransactions
-            GUARDED_BY(mMutex);
-
-    std::unordered_map<
-            sp<IBinder>,
-            std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
-            IListenerHash>
-            mPendingTransactions GUARDED_BY(mMutex);
 
     std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
-            mCompletedTransactions GUARDED_BY(mMutex);
+        mCompletedTransactions;
 
-    sp<Fence> mPresentFence GUARDED_BY(mMutex);
+    sp<Fence> mPresentFence;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 8d7e175..94e1e0c 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -161,8 +161,7 @@
                                                  Color::RED);
         transaction->setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
                 .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
-                .setBuffer(mSurfaceControl, gb)
-                .setAcquireFence(mSurfaceControl, fence)
+                .setBuffer(mSurfaceControl, gb, fence)
                 .show(mSurfaceControl)
                 .addTransactionCompletedCallback(mCallbackHelper.function,
                                                  mCallbackHelper.getContext());
@@ -312,8 +311,7 @@
     Transaction transaction;
     transaction.setLayerStack(sc, ui::DEFAULT_LAYER_STACK)
             .setLayer(sc, std::numeric_limits<int32_t>::max() - 1)
-            .setBuffer(sc, gb)
-            .setAcquireFence(sc, fence)
+            .setBuffer(sc, gb, fence)
             .show(sc)
             .addTransactionCompletedCallback(helper1.function, helper1.getContext());
 
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 965aac3..e8759e5 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -66,8 +66,7 @@
                     return err;
                 }
 
-                transaction.setBuffer(layer, buffer);
-                transaction.setAcquireFence(layer, fence);
+                transaction.setBuffer(layer, buffer, fence);
             }
 
             if (setBackgroundColor) {
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index c8eeac6..0e2bc3d 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -1353,7 +1353,7 @@
         return;
     }
 
-    Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+    Transaction().setBuffer(layer, buffer, fence).apply();
 
     status_t status = fence->wait(1000);
     ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
@@ -1375,7 +1375,7 @@
 
     sp<Fence> fence = Fence::NO_FENCE;
 
-    Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+    Transaction().setBuffer(layer, buffer, fence).apply();
 
     auto shot = getScreenCapture();
     shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index c4d42fa..3847a51 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -85,9 +85,7 @@
                              sp<Fence> fence, CallbackHelper& callback, const ReleaseCallbackId& id,
                              ReleaseBufferCallbackHelper& releaseCallback) {
         Transaction t;
-        t.setFrameNumber(layer, id.framenumber);
-        t.setBuffer(layer, buffer, id, releaseCallback.getCallback());
-        t.setAcquireFence(layer, fence);
+        t.setBuffer(layer, buffer, fence, id.framenumber, id, releaseCallback.getCallback());
         t.addTransactionCompletedCallback(callback.function, callback.getContext());
         t.apply();
     }
@@ -302,8 +300,8 @@
     nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
 
     Transaction t;
-    t.setBuffer(layer, firstBuffer, firstBufferCallbackId, releaseCallback->getCallback());
-    t.setAcquireFence(layer, Fence::NO_FENCE);
+    t.setBuffer(layer, firstBuffer, std::nullopt, std::nullopt, firstBufferCallbackId,
+                releaseCallback->getCallback());
     t.addTransactionCompletedCallback(transactionCallback.function,
                                       transactionCallback.getContext());
     t.setDesiredPresentTime(time);
@@ -318,8 +316,8 @@
     // Dropping frames in transaction queue emits a callback
     sp<GraphicBuffer> secondBuffer = getBuffer();
     ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
-    t.setBuffer(layer, secondBuffer, secondBufferCallbackId, releaseCallback->getCallback());
-    t.setAcquireFence(layer, Fence::NO_FENCE);
+    t.setBuffer(layer, secondBuffer, std::nullopt, std::nullopt, secondBufferCallbackId,
+                releaseCallback->getCallback());
     t.addTransactionCompletedCallback(transactionCallback.function,
                                       transactionCallback.getContext());
     t.setDesiredPresentTime(time);
@@ -361,10 +359,8 @@
     ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
 
     Transaction transaction1;
-    transaction1.setFrameNumber(layer, secondBufferCallbackId.framenumber);
-    transaction1.setBuffer(layer, secondBuffer, secondBufferCallbackId,
-                           releaseCallback->getCallback());
-    transaction1.setAcquireFence(layer, Fence::NO_FENCE);
+    transaction1.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+                           secondBufferCallbackId, releaseCallback->getCallback());
     transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext());
 
     // Set a different TransactionCompletedListener to mimic a second process
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 35033ea..e388a6f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -21,7 +21,6 @@
 #include <gtest/gtest.h>
 #include <gui/LayerMetadata.h>
 
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "EffectLayer.h"
 #include "Layer.h"
@@ -60,7 +59,6 @@
     static constexpr int32_t PRIORITY_UNSET = -1;
 
     void setupScheduler();
-    sp<BufferQueueLayer> createBufferQueueLayer();
     sp<BufferStateLayer> createBufferStateLayer();
     sp<EffectLayer> createEffectLayer();
 
@@ -90,12 +88,6 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-sp<BufferQueueLayer> RefreshRateSelectionTest::createBufferQueueLayer() {
-    sp<Client> client;
-    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
-                           LAYER_FLAGS, LayerMetadata());
-    return new BufferQueueLayer(args);
-}
 
 sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() {
     sp<Client> client;
@@ -149,46 +141,6 @@
 /* ------------------------------------------------------------------------
  * Test cases
  */
-TEST_F(RefreshRateSelectionTest, testPriorityOnBufferQueueLayers) {
-    mParent = createBufferQueueLayer();
-    mChild = createBufferQueueLayer();
-    setParent(mChild.get(), mParent.get());
-    mGrandChild = createBufferQueueLayer();
-    setParent(mGrandChild.get(), mChild.get());
-
-    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
-    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
-    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
-
-    // Child has its own priority.
-    mGrandChild->setFrameRateSelectionPriority(1);
-    commitTransaction(mGrandChild.get());
-    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
-    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
-    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
-
-    // Child inherits from his parent.
-    mChild->setFrameRateSelectionPriority(1);
-    commitTransaction(mChild.get());
-    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
-    commitTransaction(mGrandChild.get());
-
-    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
-    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
-    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
-
-    // Grandchild inherits from his grand parent.
-    mParent->setFrameRateSelectionPriority(1);
-    commitTransaction(mParent.get());
-    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
-    commitTransaction(mChild.get());
-    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
-    commitTransaction(mGrandChild.get());
-    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
-    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
-    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
-}
-
 TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) {
     mParent = createBufferStateLayer();
     mChild = createBufferStateLayer();
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index a4e9d20..84fa1e2 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -24,7 +24,6 @@
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
-#include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
 #include "EffectLayer.h"
 #include "Layer.h"
@@ -65,17 +64,6 @@
     static constexpr uint32_t LAYER_FLAGS = 0;
 };
 
-class BufferQueueLayerFactory : public LayerFactory {
-public:
-    std::string name() override { return "BufferQueueLayer"; }
-    sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
-        sp<Client> client;
-        LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
-                               LAYER_FLAGS, LayerMetadata());
-        return new BufferQueueLayer(args);
-    }
-};
-
 class BufferStateLayerFactory : public LayerFactory {
 public:
     std::string name() override { return "BufferStateLayer"; }
@@ -417,8 +405,7 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest,
-                         testing::Values(std::make_shared<BufferQueueLayerFactory>(),
-                                         std::make_shared<BufferStateLayerFactory>(),
+                         testing::Values(std::make_shared<BufferStateLayerFactory>(),
                                          std::make_shared<EffectLayerFactory>()),
                          PrintToStringParamName);
 
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index a99dabe..1d21bd4 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -44,7 +44,7 @@
                       ISchedulerCallback& callback)
           : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr},
                       refreshRateConfigs, callback, createLayerHistory(),
-                      {.supportKernelTimer = false, .useContentDetection = true}) {}
+                      {.useContentDetection = true}) {}
 
     // Used to inject mock event thread.
     ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index a749ece..bd6a780 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -46,6 +46,7 @@
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
         setupScheduler();
         mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
+        mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     }
 
     ~TransactionFrameTracerTest() {
@@ -92,21 +93,17 @@
     }
 
     TestableSurfaceFlinger mFlinger;
-    renderengine::mock::RenderEngine mRenderEngine;
+    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
 
     FenceToFenceTimeMap fenceFactory;
-    client_cache_t mClientCache;
 
     void BLASTTransactionSendsFrameTracerEvents() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
 
         sp<Fence> fence(new Fence());
-        const auto buffer = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
+        const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
         int32_t layerId = layer->getSequence();
-        uint64_t bufferId = buffer->getBuffer()->getId();
+        uint64_t bufferId = buffer->getId();
         uint64_t frameNumber = 5;
         nsecs_t dequeueTime = 10;
         nsecs_t postTime = 20;
@@ -117,9 +114,14 @@
         EXPECT_CALL(*mFlinger.getFrameTracer(),
                     traceTimestamp(layerId, bufferId, frameNumber, postTime,
                                    FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
-        layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
-                         frameNumber, dequeueTime, FrameTimelineInfo{},
-                         nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint*/);
+        BufferData bufferData;
+        bufferData.buffer = buffer;
+        bufferData.acquireFence = fence;
+        bufferData.frameNumber = frameNumber;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, postTime, /*desiredPresentTime*/ 30, false, dequeueTime,
+                         FrameTimelineInfo{});
 
         commitTransaction(layer.get());
         bool computeVisisbleRegions;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 2a7921f..2b5b7b5 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -46,6 +46,7 @@
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
         setupScheduler();
         mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
+        mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     }
 
     ~TransactionSurfaceFrameTest() {
@@ -92,10 +93,9 @@
     }
 
     TestableSurfaceFlinger mFlinger;
-    renderengine::mock::RenderEngine mRenderEngine;
+    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
 
     FenceToFenceTimeMap fenceFactory;
-    client_cache_t mClientCache;
 
     void PresentedSurfaceFrameForBufferlessTransaction() {
         sp<BufferStateLayer> layer = createBufferStateLayer();
@@ -114,13 +114,15 @@
         sp<BufferStateLayer> layer = createBufferStateLayer();
         sp<Fence> fence(new Fence());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
-        const auto buffer = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer;
+        bufferData.acquireFence = fence;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         acquireFence->signalForTest(12);
 
         commitTransaction(layer.get());
@@ -143,27 +145,30 @@
 
         sp<Fence> fence1(new Fence());
         auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
-        const auto buffer1 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer1;
+        bufferData.acquireFence = fence1;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
         sp<Fence> fence2(new Fence());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
-        const auto buffer2 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
+        const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
         nsecs_t start = systemTime();
-        layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        bufferData.buffer = buffer2;
+        bufferData.acquireFence = fence2;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         nsecs_t end = systemTime();
         acquireFence2->signalForTest(12);
 
@@ -198,13 +203,15 @@
 
         sp<Fence> fence(new Fence());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
-        const auto buffer = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer;
+        bufferData.acquireFence = fence;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         acquireFence->signalForTest(12);
 
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -227,13 +234,15 @@
         sp<BufferStateLayer> layer = createBufferStateLayer();
         sp<Fence> fence(new Fence());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
-        const auto buffer = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer;
+        bufferData.acquireFence = fence;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
 
@@ -260,13 +269,15 @@
 
         sp<Fence> fence(new Fence());
         auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
-        const auto buffer = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer;
+        bufferData.acquireFence = fence;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 3, /*inputEventId*/ 0});
         EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -299,25 +310,28 @@
 
         sp<Fence> fence1(new Fence());
         auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
-        const auto buffer1 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer1;
+        bufferData.acquireFence = fence1;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
 
         sp<Fence> fence2(new Fence());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
-        const auto buffer2 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        bufferData.buffer = buffer2;
+        bufferData.acquireFence = fence2;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         acquireFence2->signalForTest(12);
 
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -342,27 +356,30 @@
 
         sp<Fence> fence1(new Fence());
         auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
-        const auto buffer1 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
-        layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+        BufferData bufferData;
+        bufferData.buffer = buffer1;
+        bufferData.acquireFence = fence1;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
         const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
 
         sp<Fence> fence2(new Fence());
         auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
-        const auto buffer2 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
+        const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
         auto dropStartTime1 = systemTime();
-        layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0},
-                         nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint */);
+        bufferData.buffer = buffer2;
+        bufferData.acquireFence = fence2;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0});
         auto dropEndTime1 = systemTime();
         EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
         ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -370,14 +387,15 @@
 
         sp<Fence> fence3(new Fence());
         auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3);
-        const auto buffer3 = std::make_shared<
-                renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                 1, 0),
-                                               mRenderEngine, false);
+        const auto buffer3 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
         auto dropStartTime2 = systemTime();
-        layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt,
-                         {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
-                         nullptr /* releaseBufferEndpoint */);
+        bufferData.buffer = buffer3;
+        bufferData.acquireFence = fence3;
+        bufferData.frameNumber = 1;
+        bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+        bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+        layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                         {/*vsyncId*/ 2, /*inputEventId*/ 0});
         auto dropEndTime2 = systemTime();
         acquireFence3->signalForTest(12);
 
@@ -413,16 +431,16 @@
         uint32_t surfaceFramesPendingClassification = 0;
         std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames;
         for (int i = 0; i < 10; i += 2) {
-            sp<Fence> fence1(new Fence());
-            const auto buffer1 = std::make_shared<
-                    renderengine::ExternalTexture>(new GraphicBuffer(1, 1,
-                                                                     HAL_PIXEL_FORMAT_RGBA_8888, 1,
-                                                                     0),
-                                                   mRenderEngine, false);
-            layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
-                             {/*vsyncId*/ 1, /*inputEventId*/ 0},
-                             nullptr /* releaseBufferCallback */,
-                             nullptr /* releaseBufferEndpoint */);
+            sp<Fence> fence(new Fence());
+            const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
+            BufferData bufferData;
+            bufferData.buffer = buffer;
+            bufferData.acquireFence = fence;
+            bufferData.frameNumber = 1;
+            bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+            bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+            layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+                             {/*vsyncId*/ 1, /*inputEventId*/ 0});
             layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
                                                                   /*inputEventId*/ 0},
                                                                  10);