Merge "Implement Envelope Effect Limitations APIs" into main
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 65c2914..358a191 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <input/InputTransport.h>
+#include <input/LooperInterface.h>
 #include <input/Resampler.h>
 #include <utils/Looper.h>
 
@@ -66,6 +67,16 @@
 class InputConsumerNoResampling final {
 public:
     /**
+     * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must
+     * use the constructor that takes an sp<Looper> parameter instead of
+     * std::shared_ptr<LooperInterface>.
+     */
+    explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
+                                       std::shared_ptr<LooperInterface> looper,
+                                       InputConsumerCallbacks& callbacks,
+                                       std::unique_ptr<Resampler> resampler);
+
+    /**
      * @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever
      * the event is ready to consume.
      * @param looper needs to be sp and not shared_ptr because it inherits from
@@ -108,7 +119,7 @@
 
 private:
     std::shared_ptr<InputChannel> mChannel;
-    sp<Looper> mLooper;
+    std::shared_ptr<LooperInterface> mLooper;
     InputConsumerCallbacks& mCallbacks;
     std::unique_ptr<Resampler> mResampler;
 
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7d11f76..0cd8720 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -263,7 +263,7 @@
      * Return DEAD_OBJECT if the channel's peer has been closed.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t sendMessage(const InputMessage* msg);
+    virtual status_t sendMessage(const InputMessage* msg);
 
     /* Receive a message sent by the other endpoint.
      *
@@ -275,14 +275,14 @@
      * Return DEAD_OBJECT if the channel's peer has been closed.
      * Other errors probably indicate that the channel is broken.
      */
-    android::base::Result<InputMessage> receiveMessage();
+    virtual android::base::Result<InputMessage> receiveMessage();
 
     /* Tells whether there is a message in the channel available to be received.
      *
      * This is only a performance hint and may return false negative results. Clients should not
      * rely on availability of the message based on the return value.
      */
-    bool probablyHasInput() const;
+    virtual bool probablyHasInput() const;
 
     /* Wait until there is a message in the channel.
      *
@@ -323,11 +323,12 @@
      */
     sp<IBinder> getConnectionToken() const;
 
+protected:
+    InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
+
 private:
     static std::unique_ptr<InputChannel> create(const std::string& name,
                                                 android::base::unique_fd fd, sp<IBinder> token);
-
-    InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
 };
 
 /*
diff --git a/include/input/LooperInterface.h b/include/input/LooperInterface.h
new file mode 100644
index 0000000..2d6719c
--- /dev/null
+++ b/include/input/LooperInterface.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+/**
+ * LooperInterface allows the use of TestLooper in InputConsumerNoResampling without reassigning to
+ * Looper. LooperInterface is needed to control how InputConsumerNoResampling consumes and batches
+ * InputMessages.
+ */
+class LooperInterface {
+public:
+    virtual ~LooperInterface() = default;
+
+    virtual int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+                      void* data) = 0;
+    virtual int removeFd(int fd) = 0;
+
+    virtual sp<Looper> getLooper() const = 0;
+};
+} // namespace android
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 54f687b..5680798 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -24,11 +24,111 @@
 
 namespace android {
 
+#ifdef LIBBINDER_CLIENT_CACHE
+constexpr bool kUseCache = true;
+#else
+constexpr bool kUseCache = false;
+#endif
+
 using AidlServiceManager = android::os::IServiceManager;
 using IAccessor = android::os::IAccessor;
 
+static const char* kStaticCachableList[] = {
+        "activity",
+        "android.hardware.thermal.IThermal/default",
+        "android.hardware.power.IPower/default",
+        "android.frameworks.stats.IStats/default",
+        "android.system.suspend.ISystemSuspend/default",
+        "appops",
+        "audio",
+        "batterystats",
+        "carrier_config",
+        "connectivity",
+        "content_capture",
+        "device_policy",
+        "display",
+        "dropbox",
+        "econtroller",
+        "isub",
+        "legacy_permission",
+        "location",
+        "media.extractor",
+        "media.metrics",
+        "media.player",
+        "media.resource_manager",
+        "netd_listener",
+        "netstats",
+        "network_management",
+        "nfc",
+        "package_native",
+        "performance_hint",
+        "permission",
+        "permissionmgr",
+        "permission_checker",
+        "phone",
+        "platform_compat",
+        "power",
+        "role",
+        "sensorservice",
+        "statscompanion",
+        "telephony.registry",
+        "thermalservice",
+        "time_detector",
+        "trust",
+        "uimode",
+        "virtualdevice",
+        "virtualdevice_native",
+        "webviewupdate",
+};
+
+bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
+    if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) {
+        ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
+              "implemented. serviceName: %s",
+              serviceName.c_str());
+        return false;
+    }
+    for (const char* name : kStaticCachableList) {
+        if (name == serviceName) {
+            return true;
+        }
+    }
+    return false;
+}
+
+binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
+                                                         const os::Service& service) {
+    if (!kUseCache) {
+        return binder::Status::ok();
+    }
+    if (service.getTag() == os::Service::Tag::binder) {
+        sp<IBinder> binder = service.get<os::Service::Tag::binder>();
+        if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) &&
+            binder->isBinderAlive()) {
+            return mCacheForGetService->setItem(serviceName, binder);
+        }
+    }
+    return binder::Status::ok();
+}
+
+bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName,
+                                                  os::Service* _out) {
+    if (!kUseCache) {
+        return false;
+    }
+    sp<IBinder> item = mCacheForGetService->getItem(serviceName);
+    // TODO(b/363177618): Enable caching for binders which are always null.
+    if (item != nullptr && item->isBinderAlive()) {
+        *_out = os::Service::make<os::Service::Tag::binder>(item);
+        return true;
+    }
+    return false;
+}
+
 BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceManager>& impl)
-      : mTheRealServiceManager(impl) {}
+      : mTheRealServiceManager(impl) {
+    mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>();
+}
 
 sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() {
     return mTheRealServiceManager;
@@ -44,25 +144,64 @@
 
 binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name,
                                                          os::Service* _out) {
+    if (returnIfCached(name, _out)) {
+        return binder::Status::ok();
+    }
     os::Service service;
     binder::Status status = mTheRealServiceManager->getService2(name, &service);
-    toBinderService(service, _out);
+
+    if (status.isOk()) {
+        status = toBinderService(name, service, _out);
+        if (status.isOk()) {
+            return updateCache(name, service);
+        }
+    }
     return status;
 }
 
 binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name,
                                                           os::Service* _out) {
     os::Service service;
+    if (returnIfCached(name, _out)) {
+        return binder::Status::ok();
+    }
+
     binder::Status status = mTheRealServiceManager->checkService(name, &service);
-    toBinderService(service, _out);
+    if (status.isOk()) {
+        status = toBinderService(name, service, _out);
+        if (status.isOk()) {
+            return updateCache(name, service);
+        }
+    }
     return status;
 }
 
-void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Service* _out) {
+binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
+                                                             const os::Service& in,
+                                                             os::Service* _out) {
     switch (in.getTag()) {
         case os::Service::Tag::binder: {
+            if (in.get<os::Service::Tag::binder>() == nullptr) {
+                // failed to find a service. Check to see if we have any local
+                // injected Accessors for this service.
+                os::Service accessor;
+                binder::Status status = getInjectedAccessor(name, &accessor);
+                if (!status.isOk()) {
+                    *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+                    return status;
+                }
+                if (accessor.getTag() == os::Service::Tag::accessor &&
+                    accessor.get<os::Service::Tag::accessor>() != nullptr) {
+                    ALOGI("Found local injected service for %s, will attempt to create connection",
+                          name.c_str());
+                    // Call this again using the accessor Service to get the real
+                    // service's binder into _out
+                    return toBinderService(name, accessor, _out);
+                }
+            }
+
             *_out = in;
-            break;
+            return binder::Status::ok();
         }
         case os::Service::Tag::accessor: {
             sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>();
@@ -70,7 +209,7 @@
             if (accessor == nullptr) {
                 ALOGE("Service#accessor doesn't have accessor. VM is maybe starting...");
                 *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
-                break;
+                return binder::Status::ok();
             }
             auto request = [=] {
                 os::ParcelFileDescriptor fd;
@@ -83,10 +222,15 @@
                 }
             };
             auto session = RpcSession::make();
-            session->setupPreconnectedClient(base::unique_fd{}, request);
+            status_t status = session->setupPreconnectedClient(base::unique_fd{}, request);
+            if (status != OK) {
+                ALOGE("Failed to set up preconnected binder RPC client: %s",
+                      statusToString(status).c_str());
+                return binder::Status::fromStatusT(status);
+            }
             session->setSessionSpecificRoot(accessorBinder);
             *_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
-            break;
+            return binder::Status::ok();
         }
         default: {
             LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag());
@@ -177,4 +321,4 @@
     return gUnifiedServiceManager;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index 8f3839f..47b2ec9 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -18,9 +18,87 @@
 #include <android/os/BnServiceManager.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IPCThreadState.h>
+#include <map>
+#include <memory>
 
 namespace android {
 
+class BinderCacheWithInvalidation
+      : public std::enable_shared_from_this<BinderCacheWithInvalidation> {
+    class BinderInvalidation : public IBinder::DeathRecipient {
+    public:
+        BinderInvalidation(std::weak_ptr<BinderCacheWithInvalidation> cache, const std::string& key)
+              : mCache(cache), mKey(key) {}
+
+        void binderDied(const wp<IBinder>& who) override {
+            sp<IBinder> binder = who.promote();
+            if (std::shared_ptr<BinderCacheWithInvalidation> cache = mCache.lock()) {
+                cache->removeItem(mKey, binder);
+            } else {
+                ALOGI("Binder Cache pointer expired: %s", mKey.c_str());
+            }
+        }
+
+    private:
+        std::weak_ptr<BinderCacheWithInvalidation> mCache;
+        std::string mKey;
+    };
+    struct Entry {
+        sp<IBinder> service;
+        sp<BinderInvalidation> deathRecipient;
+    };
+
+public:
+    sp<IBinder> getItem(const std::string& key) const {
+        std::lock_guard<std::mutex> lock(mCacheMutex);
+
+        if (auto it = mCache.find(key); it != mCache.end()) {
+            return it->second.service;
+        }
+        return nullptr;
+    }
+
+    bool removeItem(const std::string& key, const sp<IBinder>& who) {
+        std::lock_guard<std::mutex> lock(mCacheMutex);
+        if (auto it = mCache.find(key); it != mCache.end()) {
+            if (it->second.service == who) {
+                status_t result = who->unlinkToDeath(it->second.deathRecipient);
+                if (result != DEAD_OBJECT) {
+                    ALOGW("Unlinking to dead binder resulted in: %d", result);
+                }
+                mCache.erase(key);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    binder::Status setItem(const std::string& key, const sp<IBinder>& item) {
+        sp<BinderInvalidation> deathRecipient =
+                sp<BinderInvalidation>::make(shared_from_this(), key);
+
+        // linkToDeath if binder is a remote binder.
+        if (item->localBinder() == nullptr) {
+            status_t status = item->linkToDeath(deathRecipient);
+            if (status != android::OK) {
+                ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(),
+                      status);
+                return binder::Status::fromStatusT(status);
+            }
+        }
+        std::lock_guard<std::mutex> lock(mCacheMutex);
+        Entry entry = {.service = item, .deathRecipient = deathRecipient};
+        mCache[key] = entry;
+        return binder::Status::ok();
+    }
+
+    bool isClientSideCachingEnabled(const std::string& serviceName);
+
+private:
+    std::map<std::string, Entry> mCache;
+    mutable std::mutex mCacheMutex;
+};
+
 class BackendUnifiedServiceManager : public android::os::BnServiceManager {
 public:
     explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl);
@@ -58,10 +136,16 @@
     }
 
 private:
+    std::shared_ptr<BinderCacheWithInvalidation> mCacheForGetService;
     sp<os::IServiceManager> mTheRealServiceManager;
-    void toBinderService(const os::Service& in, os::Service* _out);
+    binder::Status toBinderService(const ::std::string& name, const os::Service& in,
+                                   os::Service* _out);
+    binder::Status updateCache(const std::string& serviceName, const os::Service& service);
+    bool returnIfCached(const std::string& serviceName, os::Service* _out);
 };
 
 sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager();
 
-} // namespace android
\ No newline at end of file
+android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service);
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 455a433..f0aa801 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -82,7 +82,9 @@
 
     int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1));
     if (ret < 0) {
-        return -errno;
+        int saved_errno = errno;
+        ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno));
+        return -saved_errno;
     }
     LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
 
@@ -106,6 +108,7 @@
 
     // POLLNVAL: invalid FD number, e.g. not opened.
     if (pfd[0].revents & POLLNVAL) {
+        ALOGE("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd);
         return BAD_VALUE;
     }
 
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c55dd9d..88761d7 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#include <sys/socket.h>
 #define LOG_TAG "ServiceManagerCppClient"
 
 #include <binder/IServiceManager.h>
+#include <binder/IServiceManagerUnitTestHelper.h>
 #include "BackendUnifiedServiceManager.h"
 
 #include <inttypes.h>
@@ -24,14 +26,19 @@
 #include <chrono>
 #include <condition_variable>
 
+#include <FdTrigger.h>
+#include <RpcSocketAddress.h>
 #include <android-base/properties.h>
+#include <android/os/BnAccessor.h>
 #include <android/os/BnServiceCallback.h>
+#include <android/os/BnServiceManager.h>
 #include <android/os/IAccessor.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
+#include <binder/RpcSession.h>
 #include <utils/String8.h>
-
+#include <variant>
 #ifndef __ANDROID_VNDK__
 #include <binder/IPermissionController.h>
 #endif
@@ -148,8 +155,142 @@
     }
 };
 
+class AccessorProvider {
+public:
+    AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {}
+    sp<IBinder> provide(const String16& name) { return mProvider(name); }
+
+private:
+    AccessorProvider() = delete;
+
+    RpcAccessorProvider mProvider;
+};
+
+class AccessorProviderEntry {
+public:
+    AccessorProviderEntry(std::shared_ptr<AccessorProvider>&& provider)
+          : mProvider(std::move(provider)) {}
+    std::shared_ptr<AccessorProvider> mProvider;
+
+private:
+    AccessorProviderEntry() = delete;
+};
+
 [[clang::no_destroy]] static std::once_flag gSmOnce;
 [[clang::no_destroy]] static sp<IServiceManager> gDefaultServiceManager;
+[[clang::no_destroy]] static std::mutex gAccessorProvidersMutex;
+[[clang::no_destroy]] static std::vector<AccessorProviderEntry> gAccessorProviders;
+
+class LocalAccessor : public android::os::BnAccessor {
+public:
+    LocalAccessor(const String16& instance, RpcSocketAddressProvider&& connectionInfoProvider)
+          : mInstance(instance), mConnectionInfoProvider(std::move(connectionInfoProvider)) {
+        LOG_ALWAYS_FATAL_IF(!mConnectionInfoProvider,
+                            "LocalAccessor object needs a valid connection info provider");
+    }
+
+    ~LocalAccessor() {
+        if (mOnDelete) mOnDelete();
+    }
+
+    ::android::binder::Status addConnection(::android::os::ParcelFileDescriptor* outFd) {
+        using android::os::IAccessor;
+        sockaddr_storage addrStorage;
+        std::unique_ptr<FdTrigger> trigger = FdTrigger::make();
+        RpcTransportFd fd;
+        status_t status =
+                mConnectionInfoProvider(mInstance, reinterpret_cast<sockaddr*>(&addrStorage),
+                                        sizeof(addrStorage));
+        if (status != OK) {
+            const std::string error = "The connection info provider was unable to provide "
+                                      "connection info for instance " +
+                    std::string(String8(mInstance).c_str()) +
+                    " with status: " + statusToString(status);
+            ALOGE("%s", error.c_str());
+            return Status::fromServiceSpecificError(IAccessor::ERROR_CONNECTION_INFO_NOT_FOUND,
+                                                    error.c_str());
+        }
+        if (addrStorage.ss_family == AF_VSOCK) {
+            sockaddr_vm* addr = reinterpret_cast<sockaddr_vm*>(&addrStorage);
+            status = singleSocketConnection(VsockSocketAddress(addr->svm_cid, addr->svm_port),
+                                            trigger, &fd);
+        } else if (addrStorage.ss_family == AF_UNIX) {
+            sockaddr_un* addr = reinterpret_cast<sockaddr_un*>(&addrStorage);
+            status = singleSocketConnection(UnixSocketAddress(addr->sun_path), trigger, &fd);
+        } else if (addrStorage.ss_family == AF_INET) {
+            sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&addrStorage);
+            status = singleSocketConnection(InetSocketAddress(reinterpret_cast<sockaddr*>(addr),
+                                                              sizeof(sockaddr_in),
+                                                              inet_ntoa(addr->sin_addr),
+                                                              ntohs(addr->sin_port)),
+                                            trigger, &fd);
+        } else {
+            const std::string error =
+                    "Unsupported socket family type or the ConnectionInfoProvider failed to find a "
+                    "valid address. Family type: " +
+                    std::to_string(addrStorage.ss_family);
+            ALOGE("%s", error.c_str());
+            return Status::fromServiceSpecificError(IAccessor::ERROR_UNSUPPORTED_SOCKET_FAMILY,
+                                                    error.c_str());
+        }
+        if (status != OK) {
+            const std::string error = "Failed to connect to socket for " +
+                    std::string(String8(mInstance).c_str()) +
+                    " with status: " + statusToString(status);
+            ALOGE("%s", error.c_str());
+            int err = 0;
+            if (status == -EACCES) {
+                err = IAccessor::ERROR_FAILED_TO_CONNECT_EACCES;
+            } else {
+                err = IAccessor::ERROR_FAILED_TO_CONNECT_TO_SOCKET;
+            }
+            return Status::fromServiceSpecificError(err, error.c_str());
+        }
+        *outFd = os::ParcelFileDescriptor(std::move(fd.fd));
+        return Status::ok();
+    }
+
+    ::android::binder::Status getInstanceName(String16* instance) {
+        *instance = mInstance;
+        return Status::ok();
+    }
+
+private:
+    LocalAccessor() = delete;
+    String16 mInstance;
+    RpcSocketAddressProvider mConnectionInfoProvider;
+    std::function<void()> mOnDelete;
+};
+
+android::binder::Status getInjectedAccessor(const std::string& name,
+                                            android::os::Service* service) {
+    std::vector<AccessorProviderEntry> copiedProviders;
+    {
+        std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+        copiedProviders.insert(copiedProviders.begin(), gAccessorProviders.begin(),
+                               gAccessorProviders.end());
+    }
+
+    // Unlocked to call the providers. This requires the providers to be
+    // threadsafe and not contain any references to objects that could be
+    // deleted.
+    for (const auto& provider : copiedProviders) {
+        sp<IBinder> binder = provider.mProvider->provide(String16(name.c_str()));
+        if (binder == nullptr) continue;
+        status_t status = validateAccessor(String16(name.c_str()), binder);
+        if (status != OK) {
+            ALOGE("A provider returned a binder that is not an IAccessor for instance %s. Status: "
+                  "%s",
+                  name.c_str(), statusToString(status).c_str());
+            return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+        }
+        *service = os::Service::make<os::Service::Tag::accessor>(binder);
+        return android::binder::Status::ok();
+    }
+
+    *service = os::Service::make<os::Service::Tag::accessor>(nullptr);
+    return android::binder::Status::ok();
+}
 
 sp<IServiceManager> defaultServiceManager()
 {
@@ -172,6 +313,81 @@
     }
 }
 
+sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
+        const sp<AidlServiceManager>& sm) {
+    return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm));
+}
+
+std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
+    std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+    std::shared_ptr<AccessorProvider> provider =
+            std::make_shared<AccessorProvider>(std::move(providerCallback));
+    std::weak_ptr<AccessorProvider> receipt = provider;
+    gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider)));
+
+    return receipt;
+}
+
+status_t removeAccessorProvider(std::weak_ptr<AccessorProvider> wProvider) {
+    std::shared_ptr<AccessorProvider> provider = wProvider.lock();
+    if (provider == nullptr) {
+        ALOGE("The provider supplied to removeAccessorProvider has already been removed.");
+        return NAME_NOT_FOUND;
+    }
+    std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+    size_t sizeBefore = gAccessorProviders.size();
+    gAccessorProviders.erase(std::remove_if(gAccessorProviders.begin(), gAccessorProviders.end(),
+                                            [&](AccessorProviderEntry entry) {
+                                                return entry.mProvider == provider;
+                                            }),
+                             gAccessorProviders.end());
+    if (sizeBefore == gAccessorProviders.size()) {
+        ALOGE("Failed to find an AccessorProvider for removeAccessorProvider");
+        return NAME_NOT_FOUND;
+    }
+
+    return OK;
+}
+
+status_t validateAccessor(const String16& instance, const sp<IBinder>& binder) {
+    if (binder == nullptr) {
+        ALOGE("Binder is null");
+        return BAD_VALUE;
+    }
+    sp<IAccessor> accessor = interface_cast<IAccessor>(binder);
+    if (accessor == nullptr) {
+        ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str());
+        return BAD_TYPE;
+    }
+    String16 reportedInstance;
+    Status status = accessor->getInstanceName(&reportedInstance);
+    if (!status.isOk()) {
+        ALOGE("Failed to validate the binder being used to create a new ARpc_Accessor for %s with "
+              "status: %s",
+              String8(instance).c_str(), status.toString8().c_str());
+        return NAME_NOT_FOUND;
+    }
+    if (reportedInstance != instance) {
+        ALOGE("Instance %s doesn't match the Accessor's instance of %s", String8(instance).c_str(),
+              String8(reportedInstance).c_str());
+        return NAME_NOT_FOUND;
+    }
+    return OK;
+}
+
+sp<IBinder> createAccessor(const String16& instance,
+                           RpcSocketAddressProvider&& connectionInfoProvider) {
+    // Try to create a new accessor
+    if (!connectionInfoProvider) {
+        ALOGE("Could not find an Accessor for %s and no ConnectionInfoProvider provided to "
+              "create a new one",
+              String8(instance).c_str());
+        return nullptr;
+    }
+    sp<IBinder> binder = sp<LocalAccessor>::make(instance, std::move(connectionInfoProvider));
+    return binder;
+}
+
 #if !defined(__ANDROID_VNDK__)
 // IPermissionController is not accessible to vendors
 
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 49def82..cd21a91 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -589,6 +589,21 @@
 status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
                                               const std::vector<uint8_t>& sessionId,
                                               bool incoming) {
+    RpcTransportFd transportFd;
+    status_t status = singleSocketConnection(addr, mShutdownTrigger, &transportFd);
+    if (status != OK) return status;
+
+    return initAndAddConnection(std::move(transportFd), sessionId, incoming);
+}
+
+status_t singleSocketConnection(const RpcSocketAddress& addr,
+                                const std::unique_ptr<FdTrigger>& shutdownTrigger,
+                                RpcTransportFd* outFd) {
+    LOG_ALWAYS_FATAL_IF(outFd == nullptr,
+                        "There is no reason to call this function without an outFd");
+    LOG_ALWAYS_FATAL_IF(shutdownTrigger == nullptr,
+                        "FdTrigger argument is required so we don't get stuck in the connect call "
+                        "if the server process shuts down.");
     for (size_t tries = 0; tries < 5; tries++) {
         if (tries > 0) usleep(10000);
 
@@ -620,7 +635,7 @@
             if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
                 // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
                 // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
-                status_t pollStatus = mShutdownTrigger->triggerablePoll(transportFd, POLLOUT);
+                status_t pollStatus = shutdownTrigger->triggerablePoll(transportFd, POLLOUT);
                 if (pollStatus != OK) {
                     ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
                           statusToString(pollStatus).c_str());
@@ -654,7 +669,8 @@
         LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(),
                        transportFd.fd.get());
 
-        return initAndAddConnection(std::move(transportFd), sessionId, incoming);
+        *outFd = std::move(transportFd);
+        return OK;
     }
 
     ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h
index c7ba5d9..ee7d448 100644
--- a/libs/binder/RpcSocketAddress.h
+++ b/libs/binder/RpcSocketAddress.h
@@ -113,4 +113,11 @@
     unsigned int mPort;
 };
 
+/**
+ * Connects to a single socket and produces a RpcTransportFd.
+ */
+status_t singleSocketConnection(const RpcSocketAddress& address,
+                                const std::unique_ptr<FdTrigger>& shutdownTrigger,
+                                RpcTransportFd* outFd);
+
 } // namespace android
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 1256173..95a5da2 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -133,6 +133,9 @@
     {
       "name": "binder_sdk_test",
       "host": true
+    },
+    {
+      "name": "binderCacheUnitTest"
     }
   ],
   "imports": [
diff --git a/libs/binder/aidl/android/os/IAccessor.aidl b/libs/binder/aidl/android/os/IAccessor.aidl
index a3134a3..c06e05c 100644
--- a/libs/binder/aidl/android/os/IAccessor.aidl
+++ b/libs/binder/aidl/android/os/IAccessor.aidl
@@ -25,15 +25,56 @@
  */
 interface IAccessor {
     /**
+     * The connection info was not available for this service.
+     * This happens when the user-supplied callback fails to produce
+     * valid connection info.
+     * Depending on the implementation of the callback, it might be helpful
+     * to retry.
+     */
+    const int ERROR_CONNECTION_INFO_NOT_FOUND = 0;
+    /**
+     * Failed to create the socket. Often happens when the process trying to create
+     * the socket lacks the permissions to do so.
+     * This may be a temporary issue, so retrying the operation is OK.
+     */
+    const int ERROR_FAILED_TO_CREATE_SOCKET = 1;
+    /**
+     * Failed to connect to the socket. This can happen for many reasons, so be sure
+     * log the error message and check it.
+     * This may be a temporary issue, so retrying the operation is OK.
+     */
+    const int ERROR_FAILED_TO_CONNECT_TO_SOCKET = 2;
+    /**
+     * Failed to connect to the socket with EACCES because this process does not
+     * have perimssions to connect.
+     * There is no need to retry the connection as this access will not be granted
+     * upon retry.
+     */
+    const int ERROR_FAILED_TO_CONNECT_EACCES = 3;
+    /**
+     * Unsupported socket family type returned.
+     * There is no need to retry the connection as this socket family is not
+     * supported.
+     */
+    const int ERROR_UNSUPPORTED_SOCKET_FAMILY = 4;
+
+    /**
      * Adds a connection to the RPC server of the service managed by the IAccessor.
      *
      * This method can be called multiple times to establish multiple distinct
      * connections to the same RPC server.
      *
+     * @throws ServiceSpecificError with message and one of the IAccessor::ERROR_ values.
+     *
      * @return A file descriptor connected to the RPC session of the service managed
      *         by IAccessor.
      */
     ParcelFileDescriptor addConnection();
 
-    // TODO(b/350941051): Add API for debugging.
+    /**
+     * Get the instance name for the service this accessor is responsible for.
+     *
+     * This is used to verify the proxy binder is associated with the expected instance name.
+     */
+    String getInstanceName();
 }
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5fb7307..879f319 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -17,14 +17,16 @@
 #pragma once
 #include <binder/Common.h>
 #include <binder/IInterface.h>
-#include <utils/Vector.h>
+// Trusty has its own definition of socket APIs from trusty_ipc.h
+#ifndef __TRUSTY__
+#include <sys/socket.h>
+#endif // __TRUSTY__
 #include <utils/String16.h>
+#include <utils/Vector.h>
 #include <optional>
 
 namespace android {
 
-// ----------------------------------------------------------------------
-
 /**
  * Service manager for C++ services.
  *
@@ -216,6 +218,64 @@
 LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, uid_t uid,
                                         bool logPermissionFailure = true);
 
+// ----------------------------------------------------------------------
+// Trusty's definition of the socket APIs does not include sockaddr types
+#ifndef __TRUSTY__
+typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)>
+        RpcSocketAddressProvider;
+
+typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider;
+
+class AccessorProvider;
+
+/**
+ * Register an accessor provider for the service manager APIs.
+ *
+ * \param provider callback that generates Accessors.
+ *
+ * \return A pointer used as a recept for the successful addition of the
+ *         AccessorProvider. This is needed to unregister it later.
+ */
+[[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr<AccessorProvider> addAccessorProvider(
+        RpcAccessorProvider&& providerCallback);
+
+/**
+ * Remove an accessor provider using the pointer provided by addAccessorProvider
+ * along with the cookie pointer that was used.
+ *
+ * \param provider cookie that was returned by addAccessorProvider to keep track
+ *        of this instance.
+ */
+[[nodiscard]] LIBBINDER_EXPORTED status_t
+removeAccessorProvider(std::weak_ptr<AccessorProvider> provider);
+
+/**
+ * Create an Accessor associated with a service that can create a socket connection based
+ * on the connection info from the supplied RpcSocketAddressProvider.
+ *
+ * \param instance name of the service that this Accessor is associated with
+ * \param connectionInfoProvider a callback that returns connection info for
+ *        connecting to the service.
+ * \return the binder of the IAccessor implementation from libbinder
+ */
+LIBBINDER_EXPORTED sp<IBinder> createAccessor(const String16& instance,
+                                              RpcSocketAddressProvider&& connectionInfoProvider);
+
+/**
+ * Check to make sure this binder is the expected binder that is an IAccessor
+ * associated with a specific instance.
+ *
+ * This helper function exists to avoid adding the IAccessor type to
+ * libbinder_ndk.
+ *
+ * \param instance name of the service that this Accessor should be associated with
+ * \param binder to validate
+ *
+ * \return OK if the binder is an IAccessor for `instance`
+ */
+LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder);
+#endif // __TRUSTY__
+
 #ifndef __ANDROID__
 // Create an IServiceManager that delegates the service manager on the device via adb.
 // This is can be set as the default service manager at program start, so that
diff --git a/libs/binder/include/binder/IServiceManagerUnitTestHelper.h b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h
new file mode 100644
index 0000000..ff25163
--- /dev/null
+++ b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/os/IServiceManager.h>
+#include "IServiceManager.h"
+namespace android {
+
+/**
+ * Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing.
+ */
+LIBBINDER_EXPORTED sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
+        const sp<os::IServiceManager>& sm);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 4e02ace..5f45cb2 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -230,12 +230,24 @@
     },
     apex_available: [
         "//apex_available:platform",
+        "//apex_available:anyapex",
         "com.android.media",
         "com.android.media.swcodec",
     ],
     min_sdk_version: "29",
 }
 
+// TODO: if you try to export libbinder_headers_platform_shared from libbinder_ndk.ndk, it will
+// not select the NDK variant of libbinder_headers_platform_shared and instead, it will error
+// that the NDK can't depend on glibc C++.
+cc_library_headers {
+    name: "libbinder_headers_platform_shared_ndk",
+    export_include_dirs: ["include_cpp"],
+    sdk_version: "29",
+    min_sdk_version: "29",
+    visibility: [":__subpackages__"],
+}
+
 ndk_headers {
     name: "libbinder_ndk_headers",
     from: "include_ndk/android",
@@ -246,26 +258,14 @@
     license: "NOTICE",
 }
 
-// TODO(b/160624671): package with the aidl compiler
-ndk_headers {
-    name: "libbinder_ndk_helper_headers",
-    from: "include_cpp/android",
-    to: "android",
-    srcs: [
-        "include_cpp/android/*.h",
-    ],
-    license: "NOTICE",
-    // These are intentionally not C. It's a mistake that they're in the NDK.
-    // See the bug above.
-    skip_verification: true,
-}
+// include_cpp are packaged in development/build/sdk.atree with the AIDL compiler
 
 ndk_library {
     name: "libbinder_ndk",
     symbol_file: "libbinder_ndk.map.txt",
     first_version: "29",
     export_header_libs: [
-        "libbinder_ndk_headers",
-        "libbinder_ndk_helper_headers",
+        // used to be part of the NDK, platform things depend on it
+        "libbinder_headers_platform_shared_ndk",
     ],
 }
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 340014a..04f1517 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -195,7 +195,7 @@
 
 impl PartialEq for SpIBinder {
     fn eq(&self, other: &Self) -> bool {
-        ptr::eq(self.0.as_ptr(), other.0.as_ptr())
+        self.cmp(other) == Ordering::Equal
     }
 }
 
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 1e463a4..0e653af 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -51,6 +51,30 @@
     ],
 }
 
+cc_test {
+    name: "binderCacheUnitTest",
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: [
+        "binderCacheUnitTest.cpp",
+    ],
+    shared_libs: [
+        "liblog",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+    static_libs: [
+        "libfakeservicemanager",
+    ],
+    defaults: ["libbinder_client_cache_flag"],
+    test_suites: ["general-tests"],
+    require_root: true,
+}
+
 // unit test only, which can run on host and doesn't use /dev/binder
 cc_test {
     name: "binderUnitTest",
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
new file mode 100644
index 0000000..92dab19
--- /dev/null
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <android/os/IServiceManager.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IServiceManagerUnitTestHelper.h>
+#include "fakeservicemanager/FakeServiceManager.h"
+
+#include <sys/prctl.h>
+#include <thread>
+
+using namespace android;
+
+#ifdef LIBBINDER_CLIENT_CACHE
+constexpr bool kUseLibbinderCache = true;
+#else
+constexpr bool kUseLibbinderCache = false;
+#endif
+
+// A service name which is in the static list of cachable services
+const String16 kCachedServiceName = String16("isub");
+
+#define EXPECT_OK(status)                 \
+    do {                                  \
+        binder::Status stat = (status);   \
+        EXPECT_TRUE(stat.isOk()) << stat; \
+    } while (false)
+
+const String16 kServerName = String16("binderCacheUnitTest");
+
+class FooBar : public BBinder {
+public:
+    status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t) {
+        // exit the server
+        std::thread([] { exit(EXIT_FAILURE); }).detach();
+        return OK;
+    }
+    void killServer(sp<IBinder> binder) {
+        Parcel data, reply;
+        binder->transact(0, data, &reply, 0);
+    }
+};
+
+class MockAidlServiceManager : public os::IServiceManagerDefault {
+public:
+    MockAidlServiceManager() : innerSm() {}
+
+    binder::Status checkService(const ::std::string& name, os::Service* _out) override {
+        sp<IBinder> binder = innerSm.getService(String16(name.c_str()));
+        *_out = os::Service::make<os::Service::Tag::binder>(binder);
+        return binder::Status::ok();
+    }
+
+    binder::Status addService(const std::string& name, const sp<IBinder>& service,
+                              bool allowIsolated, int32_t dumpPriority) override {
+        return binder::Status::fromStatusT(
+                innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority));
+    }
+
+    FakeServiceManager innerSm;
+};
+
+class LibbinderCacheTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        sp<MockAidlServiceManager> sm = sp<MockAidlServiceManager>::make();
+        mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(sm);
+    }
+
+    void TearDown() override {}
+
+public:
+    void cacheAndConfirmCacheHit(const sp<IBinder>& binder1, const sp<IBinder>& binder2) {
+        // Add a service
+        EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+        // Get the service. This caches it.
+        sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+        ASSERT_EQ(binder1, result);
+
+        // Add the different binder and replace the service.
+        // The cache should still hold the original binder.
+        EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+        result = mServiceManager->checkService(kCachedServiceName);
+        if (kUseLibbinderCache) {
+            // If cache is enabled, we should get the binder to Service Manager.
+            EXPECT_EQ(binder1, result);
+        } else {
+            // If cache is disabled, then we should get the newer binder
+            EXPECT_EQ(binder2, result);
+        }
+    }
+
+    sp<android::IServiceManager> mServiceManager;
+};
+
+TEST_F(LibbinderCacheTest, AddLocalServiceAndConfirmCacheHit) {
+    sp<IBinder> binder1 = sp<BBinder>::make();
+    sp<IBinder> binder2 = sp<BBinder>::make();
+
+    cacheAndConfirmCacheHit(binder1, binder2);
+}
+
+TEST_F(LibbinderCacheTest, AddRemoteServiceAndConfirmCacheHit) {
+    sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+    ASSERT_NE(binder1, nullptr);
+    sp<IBinder> binder2 = IInterface::asBinder(mServiceManager);
+
+    cacheAndConfirmCacheHit(binder1, binder2);
+}
+
+TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) {
+    sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+    FooBar foo = FooBar();
+
+    EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1));
+
+    // Check Service, this caches the binder
+    sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+    ASSERT_EQ(binder1, result);
+
+    // Kill the server, this should remove from cache.
+    foo.killServer(binder1);
+    pid_t pid;
+    ASSERT_EQ(OK, binder1->getDebugPid(&pid));
+    system(("kill -9 " + std::to_string(pid)).c_str());
+
+    sp<IBinder> binder2 = sp<BBinder>::make();
+
+    // Add new service with the same name.
+    // This will replace the service in FakeServiceManager.
+    EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+    // Confirm that new service is returned instead of old.
+    sp<IBinder> result2 = mServiceManager->checkService(kCachedServiceName);
+    ASSERT_EQ(binder2, result2);
+}
+
+TEST_F(LibbinderCacheTest, NullBinderNotCached) {
+    sp<IBinder> binder1 = nullptr;
+    sp<IBinder> binder2 = sp<BBinder>::make();
+
+    // Check for a cacheble service which isn't registered.
+    // FakeServiceManager should return nullptr.
+    // This shouldn't be cached.
+    sp<IBinder> result = mServiceManager->checkService(kCachedServiceName);
+    ASSERT_EQ(binder1, result);
+
+    // Add the same service
+    EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
+
+    // This should return the newly added service.
+    result = mServiceManager->checkService(kCachedServiceName);
+    EXPECT_EQ(binder2, result);
+}
+
+TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) {
+    sp<IBinder> binder1 = sp<BBinder>::make();
+    sp<IBinder> binder2 = sp<BBinder>::make();
+    String16 serviceName = String16("NewLibbinderCacheTest");
+    // Add a service
+    EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder1));
+    // Get the service. This shouldn't caches it.
+    sp<IBinder> result = mServiceManager->checkService(serviceName);
+    ASSERT_EQ(binder1, result);
+
+    // Add the different binder and replace the service.
+    EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder2));
+
+    // Confirm that we get the new service
+    result = mServiceManager->checkService(serviceName);
+    EXPECT_EQ(binder2, result);
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+        // Start a FooBar service and add it to the servicemanager.
+        sp<IBinder> server = new FooBar();
+        defaultServiceManager()->addService(kServerName, server);
+
+        IPCThreadState::self()->joinThreadPool(true);
+        exit(1); // should not reach
+    }
+
+    status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(3);
+    ProcessState::self()->startThreadPool();
+    CHECK_EQ(ProcessState::self()->isThreadPoolStarted(), true);
+    CHECK_GT(ProcessState::self()->getThreadPoolMaxTotalThreadCount(), 0);
+
+    auto binder = defaultServiceManager()->waitForService(kServerName);
+    CHECK_NE(nullptr, binder.get());
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3038de9..fbca35e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -365,26 +365,57 @@
         session->setMaxOutgoingConnections(options.numOutgoingConnections);
         session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode);
 
+        sockaddr_storage addr{};
+        socklen_t addrLen = 0;
+
         switch (socketType) {
-            case SocketType::PRECONNECTED:
+            case SocketType::PRECONNECTED: {
+                sockaddr_un addr_un{};
+                addr_un.sun_family = AF_UNIX;
+                strcpy(addr_un.sun_path, serverConfig.addr.c_str());
+                addr = *reinterpret_cast<sockaddr_storage*>(&addr_un);
+                addrLen = sizeof(sockaddr_un);
+
                 status = session->setupPreconnectedClient({}, [=]() {
                     return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
                 });
-                break;
+            } break;
             case SocketType::UNIX_RAW:
-            case SocketType::UNIX:
+            case SocketType::UNIX: {
+                sockaddr_un addr_un{};
+                addr_un.sun_family = AF_UNIX;
+                strcpy(addr_un.sun_path, serverConfig.addr.c_str());
+                addr = *reinterpret_cast<sockaddr_storage*>(&addr_un);
+                addrLen = sizeof(sockaddr_un);
+
                 status = session->setupUnixDomainClient(serverConfig.addr.c_str());
-                break;
+            } break;
             case SocketType::UNIX_BOOTSTRAP:
                 status = session->setupUnixDomainSocketBootstrapClient(
                         unique_fd(dup(bootstrapClientFd.get())));
                 break;
-            case SocketType::VSOCK:
+            case SocketType::VSOCK: {
+                sockaddr_vm addr_vm{
+                        .svm_family = AF_VSOCK,
+                        .svm_port = static_cast<unsigned int>(serverInfo.port),
+                        .svm_cid = VMADDR_CID_LOCAL,
+                };
+                addr = *reinterpret_cast<sockaddr_storage*>(&addr_vm);
+                addrLen = sizeof(sockaddr_vm);
+
                 status = session->setupVsockClient(VMADDR_CID_LOCAL, serverInfo.port);
-                break;
-            case SocketType::INET:
-                status = session->setupInetClient("127.0.0.1", serverInfo.port);
-                break;
+            } break;
+            case SocketType::INET: {
+                const std::string ip_addr = "127.0.0.1";
+                sockaddr_in addr_in{};
+                addr_in.sin_family = AF_INET;
+                addr_in.sin_port = htons(serverInfo.port);
+                inet_aton(ip_addr.c_str(), &addr_in.sin_addr);
+                addr = *reinterpret_cast<sockaddr_storage*>(&addr_in);
+                addrLen = sizeof(sockaddr_in);
+
+                status = session->setupInetClient(ip_addr.c_str(), serverInfo.port);
+            } break;
             case SocketType::TIPC:
                 status = session->setupPreconnectedClient({}, [=]() {
 #ifdef BINDER_RPC_TO_TRUSTY_TEST
@@ -413,7 +444,7 @@
             break;
         }
         LOG_ALWAYS_FATAL_IF(status != OK, "Could not connect: %s", statusToString(status).c_str());
-        ret->sessions.push_back({session, session->getRootObject()});
+        ret->sessions.push_back({session, session->getRootObject(), addr, addrLen});
     }
     return ret;
 }
@@ -1127,6 +1158,139 @@
     ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
 }
 
+// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel
+#ifdef BINDER_WITH_KERNEL_IPC
+
+class BinderRpcAccessor : public BinderRpc {
+    void SetUp() override {
+        if (serverSingleThreaded()) {
+            // This blocks on android::FdTrigger::triggerablePoll when attempting to set
+            // up the client RpcSession
+            GTEST_SKIP() << "Accessors are not supported for single threaded libbinder";
+        }
+        if (rpcSecurity() == RpcSecurity::TLS) {
+            GTEST_SKIP() << "Accessors are not supported with TLS";
+            // ... for now
+        }
+
+        if (socketType() == SocketType::UNIX_BOOTSTRAP) {
+            GTEST_SKIP() << "Accessors do not support UNIX_BOOTSTRAP because no connection "
+                            "information is known";
+        }
+        if (socketType() == SocketType::TIPC) {
+            GTEST_SKIP() << "Accessors do not support TIPC because the socket transport is not "
+                            "known in libbinder";
+        }
+        BinderRpc::SetUp();
+    }
+};
+
+inline void waitForExtraSessionCleanup(const BinderRpcTestProcessSession& proc) {
+    // Need to give the server some time to delete its RpcSession after our last
+    // reference is dropped, closing the connection. Check for up to 1 second,
+    // every 10 ms.
+    for (size_t i = 0; i < 100; i++) {
+        std::vector<int32_t> remoteCounts;
+        EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
+        // We exect the original binder to still be alive, we just want to wait
+        // for this extra session to be cleaned up.
+        if (remoteCounts.size() == proc.proc->sessions.size()) break;
+        usleep(10000);
+    }
+}
+
+TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) {
+    constexpr size_t kNumThreads = 10;
+    const String16 kInstanceName("super.cool.service/better_than_default");
+
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
+        return createAccessor(name,
+                              [&](const String16& name, sockaddr* outAddr,
+                                  socklen_t addrSize) -> status_t {
+                                  if (outAddr == nullptr ||
+                                      addrSize < proc.proc->sessions[0].addrLen) {
+                                      return BAD_VALUE;
+                                  }
+                                  if (name == kInstanceName) {
+                                      if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) {
+                                          sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
+                                                  &proc.proc->sessions[0].addr);
+                                          ALOGE("inside callback: %s", un->sun_path);
+                                      }
+                                      std::memcpy(outAddr, &proc.proc->sessions[0].addr,
+                                                  proc.proc->sessions[0].addrLen);
+                                      return OK;
+                                  }
+                                  return NAME_NOT_FOUND;
+                              });
+    });
+
+    EXPECT_FALSE(receipt.expired());
+
+    sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+    sp<IBinderRpcTest> service = checked_interface_cast<IBinderRpcTest>(binder);
+    EXPECT_NE(service, nullptr);
+
+    sp<IBinder> out;
+    EXPECT_OK(service->repeatBinder(binder, &out));
+    EXPECT_EQ(binder, out);
+
+    out.clear();
+    binder.clear();
+    service.clear();
+
+    status_t status = removeAccessorProvider(receipt);
+    EXPECT_EQ(status, OK);
+
+    waitForExtraSessionCleanup(proc);
+}
+
+TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) {
+    const String16 kInstanceName("doesnt_matter_nothing_checks");
+
+    bool isProviderDeleted = false;
+
+    auto receipt = addAccessorProvider([&](const String16&) -> sp<IBinder> { return nullptr; });
+    EXPECT_FALSE(receipt.expired());
+
+    sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+    EXPECT_EQ(binder, nullptr);
+
+    status_t status = removeAccessorProvider(receipt);
+    EXPECT_EQ(status, OK);
+}
+
+TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
+    constexpr size_t kNumThreads = 10;
+    const String16 kInstanceName("super.cool.service/better_than_default");
+
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    bool isProviderDeleted = false;
+    bool isAccessorDeleted = false;
+
+    auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
+        return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t {
+            // don't fill in outAddr
+            return NAME_NOT_FOUND;
+        });
+    });
+
+    EXPECT_FALSE(receipt.expired());
+
+    sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+    EXPECT_EQ(binder, nullptr);
+
+    status_t status = removeAccessorProvider(receipt);
+    EXPECT_EQ(status, OK);
+}
+
+#endif // BINDER_WITH_KERNEL_IPC
+
 #ifdef BINDER_RPC_TO_TRUSTY_TEST
 
 static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
@@ -1315,6 +1479,11 @@
 INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()),
                          BinderRpc::PrintParamInfo);
 
+#ifdef BINDER_WITH_KERNEL_IPC
+INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpcAccessor, ::testing::ValuesIn(getBinderRpcParams()),
+                         BinderRpc::PrintParamInfo);
+#endif // BINDER_WITH_KERNEL_IPC
+
 class BinderRpcServerRootObject
       : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
 
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 2c9646b..c8a8acc 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -35,6 +35,12 @@
     struct SessionInfo {
         sp<RpcSession> session;
         sp<IBinder> root;
+// Trusty defines its own socket APIs in trusty_ipc.h but doesn't include
+// sockaddr types.
+#ifndef __TRUSTY__
+        sockaddr_storage addr;
+        socklen_t addrLen;
+#endif
     };
 
     // client session objects associated with other process
diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs
index 454bdf1..8288f9f 100644
--- a/libs/bufferstreams/rust/src/stream_config.rs
+++ b/libs/bufferstreams/rust/src/stream_config.rs
@@ -32,10 +32,23 @@
     pub stride: u32,
 }
 
+impl From<StreamConfig> for HardwareBufferDescription {
+    fn from(config: StreamConfig) -> Self {
+        HardwareBufferDescription::new(
+            config.width,
+            config.height,
+            config.layers,
+            config.format,
+            config.usage,
+            config.stride,
+        )
+    }
+}
+
 impl StreamConfig {
     /// Tries to create a new HardwareBuffer from settings in a [StreamConfig].
     pub fn create_hardware_buffer(&self) -> Option<HardwareBuffer> {
-        HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage)
+        HardwareBuffer::new(&(*self).into())
     }
 }
 
@@ -59,9 +72,10 @@
         assert!(maybe_buffer.is_some());
 
         let buffer = maybe_buffer.unwrap();
-        assert_eq!(config.width, buffer.width());
-        assert_eq!(config.height, buffer.height());
-        assert_eq!(config.format, buffer.format());
-        assert_eq!(config.usage, buffer.usage());
+        let description = buffer.description();
+        assert_eq!(config.width, description.width());
+        assert_eq!(config.height, description.height());
+        assert_eq!(config.format, description.format());
+        assert_eq!(config.usage, description.usage());
     }
 }
diff --git a/libs/gui/aidl/android/gui/JankData.aidl b/libs/gui/aidl/android/gui/JankData.aidl
index 7ea9d22..ec13681 100644
--- a/libs/gui/aidl/android/gui/JankData.aidl
+++ b/libs/gui/aidl/android/gui/JankData.aidl
@@ -29,7 +29,17 @@
   int jankType;
 
   /**
-   * Expected duration in nanoseconds of this frame.
+   * Time between frames in nanoseconds.
    */
   long frameIntervalNs;
+
+  /**
+   * Time allocated to the application to render this frame.
+   */
+  long scheduledAppFrameTimeNs;
+
+  /**
+   * Time taken by the application to render this frame.
+   */
+  long actualAppFrameTimeNs;
 }
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 7468401..df9b73b 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -98,4 +98,12 @@
   description: "Remove usage of IGBPs in the *Processor and Camera3*"
   bug: "342199002"
   is_fixed_read_only: true
-} # wb_camera3_and_processors
\ No newline at end of file
+} # wb_camera3_and_processors
+
+flag {
+  name: "wb_libcameraservice"
+  namespace: "core_graphics"
+  description: "Remove usage of IGBPs in the libcameraservice."
+  bug: "342197849"
+  is_fixed_read_only: true
+} # wb_libcameraservice
\ No newline at end of file
diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp
index 2ac2550..8db48d2 100644
--- a/libs/gui/tests/Choreographer_test.cpp
+++ b/libs/gui/tests/Choreographer_test.cpp
@@ -52,25 +52,23 @@
     sp<Looper> looper = Looper::prepare(0);
     Choreographer* choreographer = Choreographer::getForThread();
     VsyncCallback animationCb;
-    VsyncCallback inputCb;
-
     choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0,
                                             CALLBACK_ANIMATION);
+    VsyncCallback inputCb;
     choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0,
                                             CALLBACK_INPUT);
-
-    nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    nsecs_t currTime;
-    int pollResult;
+    auto startTime = std::chrono::system_clock::now();
     do {
-        pollResult = looper->pollOnce(16);
-        currTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) &&
-             (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) &&
-             (currTime - startTime < 3000));
-
-    ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback";
-    ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback";
+        static constexpr int32_t timeoutMs = 1000;
+        int pollResult = looper->pollOnce(timeoutMs);
+        ASSERT_TRUE((pollResult != Looper::POLL_TIMEOUT) && (pollResult != Looper::POLL_ERROR))
+                << "Failed to poll looper. Poll result = " << pollResult;
+        auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+                std::chrono::system_clock::now() - startTime);
+        ASSERT_LE(elapsedMs.count(), timeoutMs)
+                << "Timed out waiting for callbacks. inputCb=" << inputCb.callbackReceived()
+                << " animationCb=" << animationCb.callbackReceived();
+    } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()));
 
     ASSERT_EQ(inputCb.frameTime, animationCb.frameTime)
             << android::base::StringPrintf("input and animation callback frame times don't match. "
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index 99ffa68..eb41918 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "InputTransport"
+#define LOG_TAG "InputConsumerNoResampling"
 #define ATRACE_TAG ATRACE_TAG_INPUT
 
 #include <chrono>
@@ -33,8 +33,6 @@
 #include <input/PrintTools.h>
 #include <input/TraceTools.h>
 
-namespace input_flags = com::android::input::flags;
-
 namespace android {
 
 namespace {
@@ -46,6 +44,27 @@
 const bool DEBUG_TRANSPORT_CONSUMER =
         __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO);
 
+/**
+ * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper.
+ * This class' behavior is the same as Looper.
+ */
+class RealLooper final : public LooperInterface {
+public:
+    RealLooper(sp<Looper> looper) : mLooper{looper} {}
+
+    int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+              void* data) override {
+        return mLooper->addFd(fd, ident, events, callback, data);
+    }
+
+    int removeFd(int fd) override { return mLooper->removeFd(fd); }
+
+    sp<Looper> getLooper() const override { return mLooper; }
+
+private:
+    sp<Looper> mLooper;
+};
+
 std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) {
     std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>();
     event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
@@ -173,22 +192,20 @@
 bool isPointerEvent(const MotionEvent& motionEvent) {
     return (motionEvent.getSource() & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
 }
-
 } // namespace
 
 using android::base::Result;
-using android::base::StringPrintf;
 
 // --- InputConsumerNoResampling ---
 
 InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
-                                                     sp<Looper> looper,
+                                                     std::shared_ptr<LooperInterface> looper,
                                                      InputConsumerCallbacks& callbacks,
                                                      std::unique_ptr<Resampler> resampler)
-      : mChannel(channel),
-        mLooper(looper),
+      : mChannel{channel},
+        mLooper{looper},
         mCallbacks(callbacks),
-        mResampler(std::move(resampler)),
+        mResampler{std::move(resampler)},
         mFdEvents(0) {
     LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
     mCallback = sp<LooperEventCallback>::make(
@@ -199,6 +216,13 @@
     setFdEvents(ALOOPER_EVENT_INPUT);
 }
 
+InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
+                                                     sp<Looper> looper,
+                                                     InputConsumerCallbacks& callbacks,
+                                                     std::unique_ptr<Resampler> resampler)
+      : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks,
+                                  std::move(resampler)) {}
+
 InputConsumerNoResampling::~InputConsumerNoResampling() {
     ensureCalledOnLooperThread(__func__);
     consumeBatchedInputEvents(std::nullopt);
@@ -513,7 +537,7 @@
 
 void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const {
     sp<Looper> callingThreadLooper = Looper::getForThread();
-    if (callingThreadLooper != mLooper) {
+    if (callingThreadLooper != mLooper->getLooper()) {
         LOG(FATAL) << "The function " << func << " can only be called on the looper thread";
     }
 }
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 9b6fe3c..4f4ea85 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -31,6 +31,7 @@
 pub use keyboard_classifier::KeyboardClassifier;
 
 #[cxx::bridge(namespace = "android::input")]
+#[allow(clippy::needless_maybe_sized)]
 #[allow(unsafe_op_in_unsafe_fn)]
 mod ffi {
     #[namespace = "android"]
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 132866b..43bc894 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -16,6 +16,7 @@
         "BlockingQueue_test.cpp",
         "IdGenerator_test.cpp",
         "InputChannel_test.cpp",
+        "InputConsumer_test.cpp",
         "InputDevice_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
@@ -25,6 +26,8 @@
         "MotionPredictorMetricsManager_test.cpp",
         "Resampler_test.cpp",
         "RingBuffer_test.cpp",
+        "TestInputChannel.cpp",
+        "TestLooper.cpp",
         "TfLiteMotionPredictor_test.cpp",
         "TouchResampling_test.cpp",
         "TouchVideoFrame_test.cpp",
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
new file mode 100644
index 0000000..c30f243
--- /dev/null
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/InputConsumerNoResampling.h>
+
+#include <memory>
+#include <optional>
+#include <utility>
+
+#include <TestInputChannel.h>
+#include <TestLooper.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <input/BlockingQueue.h>
+#include <input/InputEventBuilders.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
+protected:
+    InputConsumerTest()
+          : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
+            mTestLooper{std::make_shared<TestLooper>()} {
+        Looper::setForThread(mTestLooper->getLooper());
+        mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper,
+                                                                *this, /*resampler=*/nullptr);
+    }
+
+    void assertOnBatchedInputEventPendingWasCalled();
+
+    std::shared_ptr<TestInputChannel> mClientTestChannel;
+    std::shared_ptr<TestLooper> mTestLooper;
+    std::unique_ptr<InputConsumerNoResampling> mConsumer;
+
+    BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
+    BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
+    BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
+    BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
+    BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
+    BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
+
+private:
+    size_t onBatchedInputEventPendingInvocationCount{0};
+
+    // InputConsumerCallbacks interface
+    void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
+        mKeyEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    }
+    void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
+        mMotionEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    }
+    void onBatchedInputEventPending(int32_t pendingBatchSource) override {
+        if (!mConsumer->probablyHasInput()) {
+            ADD_FAILURE() << "should deterministically have input because there is a batch";
+        }
+        ++onBatchedInputEventPendingInvocationCount;
+    };
+    void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
+        mFocusEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    };
+    void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
+        mCaptureEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    };
+    void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
+        mDragEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    }
+    void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
+        mTouchModeEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    };
+};
+
+void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() {
+    ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL)
+            << "onBatchedInputEventPending has not been called.";
+    --onBatchedInputEventPendingInvocationCount;
+}
+
+TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
+    mClientTestChannel->enqueueMessage(
+            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build());
+    mClientTestChannel->enqueueMessage(
+            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build());
+    mClientTestChannel->enqueueMessage(
+            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build());
+
+    mClientTestChannel->assertNoSentMessages();
+
+    mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);
+
+    assertOnBatchedInputEventPendingWasCalled();
+
+    mConsumer->consumeBatchedInputEvents(std::nullopt);
+
+    std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop();
+    ASSERT_NE(batchedMotionEvent, nullptr);
+
+    mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
+    mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+    mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+
+    EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL);
+}
+} // namespace android
diff --git a/libs/input/tests/TestInputChannel.cpp b/libs/input/tests/TestInputChannel.cpp
new file mode 100644
index 0000000..d5f00b6
--- /dev/null
+++ b/libs/input/tests/TestInputChannel.cpp
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TestInputChannel"
+#define ATRACE_TAG ATRACE_TAG_INPUT
+
+#include <TestInputChannel.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace {
+constexpr int FAKE_FD{-1};
+} // namespace
+
+// --- TestInputChannel ---
+
+TestInputChannel::TestInputChannel(const std::string& name)
+      : InputChannel{name, base::unique_fd(FAKE_FD), sp<BBinder>::make()} {}
+
+void TestInputChannel::enqueueMessage(const InputMessage& message) {
+    mReceivedMessages.push(message);
+}
+
+status_t TestInputChannel::sendMessage(const InputMessage* message) {
+    LOG_IF(FATAL, message == nullptr)
+            << "TestInputChannel " << getName() << ". No message was passed to sendMessage.";
+
+    mSentMessages.push(*message);
+    return OK;
+}
+
+base::Result<InputMessage> TestInputChannel::receiveMessage() {
+    if (mReceivedMessages.empty()) {
+        return base::Error(WOULD_BLOCK);
+    }
+    InputMessage message = mReceivedMessages.front();
+    mReceivedMessages.pop();
+    return message;
+}
+
+bool TestInputChannel::probablyHasInput() const {
+    return !mReceivedMessages.empty();
+}
+
+void TestInputChannel::assertFinishMessage(uint32_t seq, bool handled) {
+    ASSERT_FALSE(mSentMessages.empty())
+            << "TestInputChannel " << getName() << ". Cannot assert. mSentMessages is empty.";
+
+    const InputMessage& finishMessage = mSentMessages.front();
+
+    EXPECT_EQ(finishMessage.header.seq, seq)
+            << "TestInputChannel " << getName()
+            << ". Sequence mismatch. Message seq: " << finishMessage.header.seq
+            << " Expected seq: " << seq;
+
+    EXPECT_EQ(finishMessage.body.finished.handled, handled)
+            << "TestInputChannel " << getName()
+            << ". Handled value mismatch. Message val: " << std::boolalpha
+            << finishMessage.body.finished.handled << "Expected val: " << handled
+            << std::noboolalpha;
+    mSentMessages.pop();
+}
+
+void TestInputChannel::assertNoSentMessages() const {
+    ASSERT_TRUE(mSentMessages.empty());
+}
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/TestInputChannel.h b/libs/input/tests/TestInputChannel.h
new file mode 100644
index 0000000..43253ec
--- /dev/null
+++ b/libs/input/tests/TestInputChannel.h
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <queue>
+#include <string>
+
+#include <android-base/result.h>
+#include <gtest/gtest.h>
+#include <input/InputTransport.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class TestInputChannel final : public InputChannel {
+public:
+    explicit TestInputChannel(const std::string& name);
+
+    /**
+     * Enqueues a message in mReceivedMessages.
+     */
+    void enqueueMessage(const InputMessage& message);
+
+    /**
+     * Pushes message to mSentMessages. In the default implementation, InputChannel sends messages
+     * through a file descriptor. TestInputChannel, on the contrary, stores sent messages in
+     * mSentMessages for assertion reasons.
+     */
+    status_t sendMessage(const InputMessage* message) override;
+
+    /**
+     * Returns an InputMessage from mReceivedMessages. This is done instead of retrieving data
+     * directly from fd.
+     */
+    base::Result<InputMessage> receiveMessage() override;
+
+    /**
+     * Returns if mReceivedMessages is not empty.
+     */
+    bool probablyHasInput() const override;
+
+    void assertFinishMessage(uint32_t seq, bool handled);
+
+    void assertNoSentMessages() const;
+
+private:
+    // InputMessages received by the endpoint.
+    std::queue<InputMessage> mReceivedMessages;
+    // InputMessages sent by the endpoint.
+    std::queue<InputMessage> mSentMessages;
+};
+} // namespace android
diff --git a/libs/input/tests/TestLooper.cpp b/libs/input/tests/TestLooper.cpp
new file mode 100644
index 0000000..e0f01ed
--- /dev/null
+++ b/libs/input/tests/TestLooper.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <TestLooper.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+
+TestLooper::TestLooper() : mLooper(sp<Looper>::make(/*allowNonCallbacks=*/false)) {}
+
+int TestLooper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+                      void* data) {
+    mCallbacks[fd] = callback;
+    constexpr int SUCCESS{1};
+    return SUCCESS;
+}
+
+int TestLooper::removeFd(int fd) {
+    if (auto it = mCallbacks.find(fd); it != mCallbacks.cend()) {
+        mCallbacks.erase(fd);
+        constexpr int SUCCESS{1};
+        return SUCCESS;
+    }
+    constexpr int FAILURE{0};
+    return FAILURE;
+}
+
+void TestLooper::invokeCallback(int fd, int events) {
+    auto it = mCallbacks.find(fd);
+    LOG_IF(FATAL, it == mCallbacks.cend()) << "Fd does not exist in mCallbacks.";
+    mCallbacks[fd]->handleEvent(fd, events, /*data=*/nullptr);
+}
+
+sp<Looper> TestLooper::getLooper() const {
+    return mLooper;
+}
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/TestLooper.h b/libs/input/tests/TestLooper.h
new file mode 100644
index 0000000..3242bc7
--- /dev/null
+++ b/libs/input/tests/TestLooper.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <input/LooperInterface.h>
+
+namespace android {
+/**
+ * TestLooper provides a mechanism to directly trigger Looper's callback.
+ */
+class TestLooper final : public LooperInterface {
+public:
+    TestLooper();
+
+    /**
+     * Adds a file descriptor to mCallbacks. Ident, events, and data parameters are ignored. If
+     * addFd is called with an existent file descriptor and a different callback, the previous
+     * callback is overwritten.
+     */
+    int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
+              void* data) override;
+
+    /**
+     * Removes a file descriptor from mCallbacks. If fd is not in mCallbacks, returns FAILURE.
+     */
+    int removeFd(int fd) override;
+
+    /**
+     * Calls handleEvent of the file descriptor. Fd must be in mCallbacks. Otherwise, invokeCallback
+     * fatally logs.
+     */
+    void invokeCallback(int fd, int events);
+
+    sp<Looper> getLooper() const override;
+
+private:
+    std::map<int /*fd*/, sp<LooperCallback>> mCallbacks;
+    sp<Looper> mLooper;
+};
+} // namespace android
\ No newline at end of file
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 8558074..a8a86ba 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -67,9 +67,6 @@
 
     // Android O
     first_version: "26",
-    export_header_libs: [
-        "libnativewindow_ndk_headers",
-    ],
 }
 
 cc_library {
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index 97740db..d68d6ba 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -29,6 +29,8 @@
         "--bitfield-enum=AHardwareBuffer_UsageFlags",
 
         "--allowlist-file=.*/nativewindow/include/.*\\.h",
+        "--allowlist-file=.*/include/cutils/.*\\.h",
+        "--allowlist-file=.*/include_outside_system/cutils/.*\\.h",
         "--blocklist-type",
         "AParcel",
         "--raw-line",
@@ -39,6 +41,7 @@
     ],
     shared_libs: [
         "libbinder_ndk",
+        "libcutils",
         "libnativewindow",
     ],
     rustlibs: [
@@ -66,6 +69,7 @@
     srcs: [":libnativewindow_bindgen_internal"],
     shared_libs: [
         "libbinder_ndk",
+        "libcutils",
         "libnativewindow",
     ],
     rustlibs: [
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
new file mode 100644
index 0000000..a3a9dc6
--- /dev/null
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -0,0 +1,92 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::{mem::forget, ptr::NonNull};
+
+/// Rust wrapper around `native_handle_t`.
+///
+/// This owns the `native_handle_t` and its file descriptors, and will close them and free it when
+/// it is dropped.
+#[derive(Debug)]
+pub struct NativeHandle(NonNull<ffi::native_handle_t>);
+
+impl NativeHandle {
+    /// Wraps a raw `native_handle_t` pointer, taking ownership of it.
+    ///
+    /// # Safety
+    ///
+    /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used
+    ///  anywhere else after calling this method.
+    pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self {
+        Self(native_handle)
+    }
+
+    /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer.
+    ///
+    /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so
+    /// the caller remains responsible for closing and freeing it.
+    ///
+    /// # Safety
+    ///
+    /// `native_handle` must be a valid pointer to a `native_handle_t`.
+    pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> {
+        // SAFETY: The caller promised that `native_handle` was valid.
+        let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) };
+        NonNull::new(cloned).map(Self)
+    }
+
+    /// Returns a raw pointer to the wrapped `native_handle_t`.
+    ///
+    /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't
+    /// be closed or deleted.
+    pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> {
+        self.0
+    }
+
+    /// Turns the `NativeHandle` into a raw `native_handle_t`.
+    ///
+    /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is
+    /// responsible for closing and freeing it.
+    pub fn into_raw(self) -> NonNull<ffi::native_handle_t> {
+        let raw = self.0;
+        forget(self);
+        raw
+    }
+}
+
+impl Clone for NativeHandle {
+    fn clone(&self) -> Self {
+        // SAFETY: Our wrapped `native_handle_t` pointer is always valid.
+        unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null")
+    }
+}
+
+impl Drop for NativeHandle {
+    fn drop(&mut self) {
+        // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+        // after this because we own it and are being dropped.
+        unsafe {
+            assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0);
+            assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+        }
+    }
+}
+
+// SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file
+// descriptors, which aren't tied to any particular thread.
+unsafe impl Send for NativeHandle {}
+
+// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
+// integers and file descriptors.
+unsafe impl Sync for NativeHandle {}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
index dc3f51f..931c311 100644
--- a/libs/nativewindow/rust/src/lib.rs
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -16,7 +16,10 @@
 
 extern crate nativewindow_bindgen as ffi;
 
+mod handle;
 mod surface;
+
+pub use handle::NativeHandle;
 pub use surface::Surface;
 
 pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
@@ -27,11 +30,86 @@
     unstable_api::{status_result, AsNative},
     StatusCode,
 };
-use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel};
+use ffi::{
+    AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
+    AHardwareBuffer_writeToParcel,
+};
 use std::fmt::{self, Debug, Formatter};
 use std::mem::ManuallyDrop;
 use std::ptr::{self, null_mut, NonNull};
 
+/// Wrapper around a C `AHardwareBuffer_Desc`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct HardwareBufferDescription(AHardwareBuffer_Desc);
+
+impl HardwareBufferDescription {
+    /// Creates a new `HardwareBufferDescription` with the given parameters.
+    pub fn new(
+        width: u32,
+        height: u32,
+        layers: u32,
+        format: AHardwareBuffer_Format::Type,
+        usage: AHardwareBuffer_UsageFlags,
+        stride: u32,
+    ) -> Self {
+        Self(AHardwareBuffer_Desc {
+            width,
+            height,
+            layers,
+            format,
+            usage: usage.0,
+            stride,
+            rfu0: 0,
+            rfu1: 0,
+        })
+    }
+
+    /// Returns the width from the buffer description.
+    pub fn width(&self) -> u32 {
+        self.0.width
+    }
+
+    /// Returns the height from the buffer description.
+    pub fn height(&self) -> u32 {
+        self.0.height
+    }
+
+    /// Returns the number from layers from the buffer description.
+    pub fn layers(&self) -> u32 {
+        self.0.layers
+    }
+
+    /// Returns the format from the buffer description.
+    pub fn format(&self) -> AHardwareBuffer_Format::Type {
+        self.0.format
+    }
+
+    /// Returns the usage bitvector from the buffer description.
+    pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+        AHardwareBuffer_UsageFlags(self.0.usage)
+    }
+
+    /// Returns the stride from the buffer description.
+    pub fn stride(&self) -> u32 {
+        self.0.stride
+    }
+}
+
+impl Default for HardwareBufferDescription {
+    fn default() -> Self {
+        Self(AHardwareBuffer_Desc {
+            width: 0,
+            height: 0,
+            layers: 0,
+            format: 0,
+            usage: 0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        })
+    }
+}
+
 /// Wrapper around an opaque C `AHardwareBuffer`.
 #[derive(PartialEq, Eq)]
 pub struct HardwareBuffer(NonNull<AHardwareBuffer>);
@@ -43,26 +121,9 @@
     /// that the allocation of the given description will never succeed.
     ///
     /// Available since API 29
-    pub fn is_supported(
-        width: u32,
-        height: u32,
-        layers: u32,
-        format: AHardwareBuffer_Format::Type,
-        usage: AHardwareBuffer_UsageFlags,
-        stride: u32,
-    ) -> bool {
-        let buffer_desc = ffi::AHardwareBuffer_Desc {
-            width,
-            height,
-            layers,
-            format,
-            usage: usage.0,
-            stride,
-            rfu0: 0,
-            rfu1: 0,
-        };
-        // SAFETY: *buffer_desc will never be null.
-        let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+    pub fn is_supported(buffer_description: &HardwareBufferDescription) -> bool {
+        // SAFETY: The pointer comes from a reference so must be valid.
+        let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_description.0) };
 
         status == 1
     }
@@ -74,27 +135,11 @@
     ///
     /// Available since API level 26.
     #[inline]
-    pub fn new(
-        width: u32,
-        height: u32,
-        layers: u32,
-        format: AHardwareBuffer_Format::Type,
-        usage: AHardwareBuffer_UsageFlags,
-    ) -> Option<Self> {
-        let buffer_desc = ffi::AHardwareBuffer_Desc {
-            width,
-            height,
-            layers,
-            format,
-            usage: usage.0,
-            stride: 0,
-            rfu0: 0,
-            rfu1: 0,
-        };
+    pub fn new(buffer_description: &HardwareBufferDescription) -> Option<Self> {
         let mut ptr = ptr::null_mut();
         // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
         // and return a status, but we check it later.
-        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) };
+        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_description.0, &mut ptr) };
 
         if status == 0 {
             Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null")))
@@ -103,6 +148,50 @@
         }
     }
 
+    /// Creates a `HardwareBuffer` from a native handle.
+    ///
+    /// The native handle is cloned, so this doesn't take ownership of the original handle passed
+    /// in.
+    pub fn create_from_handle(
+        handle: &NativeHandle,
+        buffer_description: &HardwareBufferDescription,
+    ) -> Result<Self, StatusCode> {
+        let mut buffer = ptr::null_mut();
+        // SAFETY: The caller guarantees that `handle` is valid, and the buffer pointer is valid
+        // because it comes from a reference. The method we pass means that
+        // `AHardwareBuffer_createFromHandle` will clone the handle rather than taking ownership of
+        // it.
+        let status = unsafe {
+            ffi::AHardwareBuffer_createFromHandle(
+                &buffer_description.0,
+                handle.as_raw().as_ptr(),
+                ffi::CreateFromHandleMethod_AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE
+                    .try_into()
+                    .unwrap(),
+                &mut buffer,
+            )
+        };
+        status_result(status)?;
+        Ok(Self(NonNull::new(buffer).expect("Allocated AHardwareBuffer was null")))
+    }
+
+    /// Returns a clone of the native handle of the buffer.
+    ///
+    /// Returns `None` if the operation fails for any reason.
+    pub fn cloned_native_handle(&self) -> Option<NativeHandle> {
+        // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid
+        // because it must have been allocated by `AHardwareBuffer_allocate`,
+        // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet
+        // released it.
+        let native_handle = unsafe { ffi::AHardwareBuffer_getNativeHandle(self.0.as_ptr()) };
+        NonNull::new(native_handle.cast_mut()).and_then(|native_handle| {
+            // SAFETY: `AHardwareBuffer_getNativeHandle` should have returned a valid pointer which
+            // is valid at least as long as the buffer is, and `clone_from_raw` clones it rather
+            // than taking ownership of it so the original `native_handle` isn't stored.
+            unsafe { NativeHandle::clone_from_raw(native_handle) }
+        })
+    }
+
     /// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer.
     ///
     /// # Safety
@@ -155,37 +244,8 @@
         out_id
     }
 
-    /// Get the width of this buffer
-    pub fn width(&self) -> u32 {
-        self.description().width
-    }
-
-    /// Get the height of this buffer
-    pub fn height(&self) -> u32 {
-        self.description().height
-    }
-
-    /// Get the number of layers of this buffer
-    pub fn layers(&self) -> u32 {
-        self.description().layers
-    }
-
-    /// Get the format of this buffer
-    pub fn format(&self) -> AHardwareBuffer_Format::Type {
-        self.description().format
-    }
-
-    /// Get the usage bitvector of this buffer
-    pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
-        AHardwareBuffer_UsageFlags(self.description().usage)
-    }
-
-    /// Get the stride of this buffer
-    pub fn stride(&self) -> u32 {
-        self.description().stride
-    }
-
-    fn description(&self) -> ffi::AHardwareBuffer_Desc {
+    /// Returns the description of this buffer.
+    pub fn description(&self) -> HardwareBufferDescription {
         let mut buffer_desc = ffi::AHardwareBuffer_Desc {
             width: 0,
             height: 0,
@@ -198,7 +258,7 @@
         };
         // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
         unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
-        buffer_desc
+        HardwareBufferDescription(buffer_desc)
     }
 }
 
@@ -281,19 +341,27 @@
 
     #[test]
     fn create_valid_buffer_returns_ok() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             512,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        );
+            0,
+        ));
         assert!(buffer.is_some());
     }
 
     #[test]
     fn create_invalid_buffer_returns_err() {
-        let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
+            512,
+            512,
+            1,
+            0,
+            AHardwareBuffer_UsageFlags(0),
+            0,
+        ));
         assert!(buffer.is_none());
     }
 
@@ -319,39 +387,45 @@
         // SAFETY: The pointer must be valid because it was just allocated successfully, and we
         // don't use it after calling this.
         let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) };
-        assert_eq!(buffer.width(), 1024);
+        assert_eq!(buffer.description().width(), 1024);
     }
 
     #[test]
     fn basic_getters() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
 
-        assert_eq!(buffer.width(), 1024);
-        assert_eq!(buffer.height(), 512);
-        assert_eq!(buffer.layers(), 1);
-        assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+        let description = buffer.description();
+        assert_eq!(description.width(), 1024);
+        assert_eq!(description.height(), 512);
+        assert_eq!(description.layers(), 1);
         assert_eq!(
-            buffer.usage(),
+            description.format(),
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
+        );
+        assert_eq!(
+            description.usage(),
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
         );
     }
 
     #[test]
     fn id_getter() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
 
         assert_ne!(0, buffer.id());
@@ -359,13 +433,14 @@
 
     #[test]
     fn clone() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
         let buffer2 = buffer.clone();
 
@@ -374,13 +449,14 @@
 
     #[test]
     fn into_raw() {
-        let buffer = HardwareBuffer::new(
+        let buffer = HardwareBuffer::new(&HardwareBufferDescription::new(
             1024,
             512,
             1,
             AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
             AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-        )
+            0,
+        ))
         .expect("Buffer with some basic parameters was not created successfully");
         let buffer2 = buffer.clone();
 
@@ -390,4 +466,26 @@
 
         assert_eq!(remade_buffer, buffer2);
     }
+
+    #[test]
+    fn native_handle_and_back() {
+        let buffer_description = HardwareBufferDescription::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+            1024,
+        );
+        let buffer = HardwareBuffer::new(&buffer_description)
+            .expect("Buffer with some basic parameters was not created successfully");
+
+        let native_handle =
+            buffer.cloned_native_handle().expect("Failed to get native handle for buffer");
+        let buffer2 = HardwareBuffer::create_from_handle(&native_handle, &buffer_description)
+            .expect("Failed to create buffer from native handle");
+
+        assert_eq!(buffer.description(), buffer_description);
+        assert_eq!(buffer2.description(), buffer_description);
+    }
 }
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
index 5689f7d..5046a80 100644
--- a/libs/nativewindow/rust/sys/nativewindow_bindings.h
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -20,3 +20,5 @@
 #include <android/hdr_metadata.h>
 #include <android/native_window.h>
 #include <android/native_window_aidl.h>
+#include <cutils/native_handle.h>
+#include <vndk/hardware_buffer.h>
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
index 876f6c8..73a7e95 100644
--- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -22,13 +22,14 @@
 
 #[inline]
 fn create_720p_buffer() -> HardwareBuffer {
-    HardwareBuffer::new(
+    HardwareBuffer::new(&HardwareBufferDescription::new(
         1280,
         720,
         1,
         AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
         AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
-    )
+        0,
+    ))
     .unwrap()
 }
 
@@ -51,7 +52,7 @@
     // underlying call to AHardwareBuffer_describe.
     c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| {
         b.iter(|| {
-            buffer.width();
+            buffer.description().width();
         })
     });
 }
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 326d1ce..a9264b3 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -29,6 +29,16 @@
 using namespace android;
 using namespace android::renderengine;
 
+// To run tests:
+/**
+ * mmm frameworks/native/libs/renderengine/benchmark;\
+ * adb push $OUT/data/benchmarktest/librenderengine_bench/librenderengine_bench
+ *      /data/benchmarktest/librenderengine_bench/librenderengine_bench;\
+ * adb shell /data/benchmarktest/librenderengine_bench/librenderengine_bench
+ *
+ * (64-bit devices: out directory contains benchmarktest64 instead of benchmarktest)
+ */
+
 ///////////////////////////////////////////////////////////////////////////////
 //  Helpers for calling drawLayers
 ///////////////////////////////////////////////////////////////////////////////
@@ -173,29 +183,67 @@
     }
 }
 
+/**
+ * Return a buffer with the image in the provided path, relative to the executable directory
+ */
+static std::shared_ptr<ExternalTexture> createTexture(RenderEngine& re, const char* relPathImg) {
+    // Initially use cpu access so we can decode into it with AImageDecoder.
+    auto [width, height] = getDisplaySize();
+    auto srcBuffer =
+            allocateBuffer(re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
+    std::string fileName = base::GetExecutableDirectory().append(relPathImg);
+    renderenginebench::decode(fileName.c_str(), srcBuffer->getBuffer());
+    // Now copy into GPU-only buffer for more realistic timing.
+    srcBuffer = copyBuffer(re, srcBuffer, 0, "source");
+    return srcBuffer;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //  Benchmarks
 ///////////////////////////////////////////////////////////////////////////////
 
+constexpr char kHomescreenPath[] = "/resources/homescreen.png";
+
+/**
+ * Draw a layer with texture and no additional shaders as a baseline to evaluate a shader's impact
+ * on performance
+ */
 template <class... Args>
-void BM_blur(benchmark::State& benchState, Args&&... args) {
+void BM_homescreen(benchmark::State& benchState, Args&&... args) {
     auto args_tuple = std::make_tuple(std::move(args)...);
     auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
-                                 static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)),
-                                 static_cast<RenderEngine::BlurAlgorithm>(std::get<2>(args_tuple)));
+                                 static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
 
-    // Initially use cpu access so we can decode into it with AImageDecoder.
     auto [width, height] = getDisplaySize();
-    auto srcBuffer =
-            allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source");
-    {
-        std::string srcImage = base::GetExecutableDirectory();
-        srcImage.append("/resources/homescreen.png");
-        renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer());
+    auto srcBuffer = createTexture(*re, kHomescreenPath);
 
-        // Now copy into GPU-only buffer for more realistic timing.
-        srcBuffer = copyBuffer(*re, srcBuffer, 0, "source");
-    }
+    const FloatRect layerRect(0, 0, width, height);
+    LayerSettings layer{
+            .geometry =
+                    Geometry{
+                            .boundaries = layerRect,
+                    },
+            .source =
+                    PixelSource{
+                            .buffer =
+                                    Buffer{
+                                            .buffer = srcBuffer,
+                                    },
+                    },
+            .alpha = half(1.0f),
+    };
+    auto layers = std::vector<LayerSettings>{layer};
+    benchDrawLayers(*re, layers, benchState, "homescreen");
+}
+
+template <class... Args>
+void BM_homescreen_blur(benchmark::State& benchState, Args&&... args) {
+    auto args_tuple = std::make_tuple(std::move(args)...);
+    auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+                                 static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
+
+    auto [width, height] = getDisplaySize();
+    auto srcBuffer = createTexture(*re, kHomescreenPath);
 
     const FloatRect layerRect(0, 0, width, height);
     LayerSettings layer{
@@ -223,14 +271,55 @@
     };
 
     auto layers = std::vector<LayerSettings>{layer, blurLayer};
-    benchDrawLayers(*re, layers, benchState, "blurred");
+    benchDrawLayers(*re, layers, benchState, "homescreen_blurred");
 }
 
-BENCHMARK_CAPTURE(BM_blur, gaussian, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
-                  RenderEngine::BlurAlgorithm::GAUSSIAN);
+template <class... Args>
+void BM_homescreen_edgeExtension(benchmark::State& benchState, Args&&... args) {
+    auto args_tuple = std::make_tuple(std::move(args)...);
+    auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)),
+                                 static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)));
 
-BENCHMARK_CAPTURE(BM_blur, kawase, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
-                  RenderEngine::BlurAlgorithm::KAWASE);
+    auto [width, height] = getDisplaySize();
+    auto srcBuffer = createTexture(*re, kHomescreenPath);
 
-BENCHMARK_CAPTURE(BM_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
+    LayerSettings layer{
+            .geometry =
+                    Geometry{
+                            .boundaries = FloatRect(0, 0, width, height),
+                    },
+            .source =
+                    PixelSource{
+                            .buffer =
+                                    Buffer{
+                                            .buffer = srcBuffer,
+                                            // Part of the screen is not covered by the texture but
+                                            // will be filled in by the shader
+                                            .textureTransform =
+                                                    mat4(mat3(),
+                                                         vec3(width * 0.3f, height * 0.3f, 0.0f)),
+                                    },
+                    },
+            .alpha = half(1.0f),
+            .edgeExtensionEffect =
+                    EdgeExtensionEffect(/* left */ true,
+                                        /* right  */ false, /* top */ true, /* bottom */ false),
+    };
+    auto layers = std::vector<LayerSettings>{layer};
+    benchDrawLayers(*re, layers, benchState, "homescreen_edge_extension");
+}
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, gaussian, RenderEngine::Threaded::YES,
+                  RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::GAUSSIAN);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase, RenderEngine::Threaded::YES,
+                  RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
                   RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER);
+
+BENCHMARK_CAPTURE(BM_homescreen, SkiaGLThreaded, RenderEngine::Threaded::YES,
+                  RenderEngine::GraphicsApi::GL);
+
+BENCHMARK_CAPTURE(BM_homescreen_edgeExtension, SkiaGLThreaded, RenderEngine::Threaded::YES,
+                  RenderEngine::GraphicsApi::GL);
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index 74daf47..a570ad0 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -16,9 +16,9 @@
 
 #pragma once
 
-#include <GrDirectContext.h>
 #include <SkImage.h>
 #include <SkSurface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
 #include <sys/types.h>
 #include <ui/GraphicTypes.h>
 
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index af24600..4ef7d5b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -21,16 +21,15 @@
 
 #include "SkiaGLRenderEngine.h"
 
-#include "compat/SkiaGpuContext.h"
-
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <GrContextOptions.h>
-#include <GrTypes.h>
 #include <android-base/stringprintf.h>
 #include <common/trace.h>
-#include <gl/GrGLInterface.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
 #include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
+#include <log/log_main.h>
 #include <sync/sync.h>
 #include <ui/DebugUtils.h>
 
@@ -40,7 +39,7 @@
 #include <numeric>
 
 #include "GLExtensions.h"
-#include "log/log_main.h"
+#include "compat/SkiaGpuContext.h"
 
 namespace android {
 namespace renderengine {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index bd177e6..7651038 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -20,9 +20,10 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
-#include <GrDirectContext.h>
 #include <SkSurface.h>
 #include <android-base/thread_annotations.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
 #include <renderengine/ExternalTexture.h>
 #include <renderengine/RenderEngine.h>
 #include <sys/types.h>
@@ -32,7 +33,6 @@
 
 #include "AutoBackendTexture.h"
 #include "EGL/egl.h"
-#include "GrContextOptions.h"
 #include "SkImageInfo.h"
 #include "SkiaRenderEngine.h"
 #include "android-base/macros.h"
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index d58f303..056e8fe 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,9 +20,6 @@
 
 #include "SkiaRenderEngine.h"
 
-#include <GrBackendSemaphore.h>
-#include <GrContextOptions.h>
-#include <GrTypes.h>
 #include <SkBlendMode.h>
 #include <SkCanvas.h>
 #include <SkColor.h>
@@ -56,6 +53,9 @@
 #include <common/FlagManager.h>
 #include <common/trace.h>
 #include <gui/FenceMonitor.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
 #include <include/gpu/ganesh/SkSurfaceGanesh.h>
 #include <pthread.h>
 #include <src/core/SkTraceEventCommon.h>
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 224a1ca..721dbce 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -18,11 +18,12 @@
 #define SF_SKIARENDERENGINE_H_
 
 #include <renderengine/RenderEngine.h>
-#include <sys/types.h>
 
-#include <GrBackendSemaphore.h>
-#include <SkSurface.h>
 #include <android-base/thread_annotations.h>
+#include <include/core/SkImageInfo.h>
+#include <include/core/SkSurface.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
 #include <renderengine/ExternalTexture.h>
 #include <renderengine/RenderEngine.h>
 #include <sys/types.h>
@@ -32,8 +33,6 @@
 #include <unordered_map>
 
 #include "AutoBackendTexture.h"
-#include "GrContextOptions.h"
-#include "SkImageInfo.h"
 #include "android-base/macros.h"
 #include "compat/SkiaGpuContext.h"
 #include "debug/SkiaCapture.h"
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index d89e818..677a2b6 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -24,12 +24,12 @@
 #include "GaneshVkRenderEngine.h"
 #include "compat/SkiaGpuContext.h"
 
-#include <GrBackendSemaphore.h>
-#include <GrContextOptions.h>
-#include <GrDirectContext.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
 #include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
 #include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
 
 #include <android-base/stringprintf.h>
 #include <common/trace.h>
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
index 3fbc6ca..88282e7 100644
--- a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
@@ -21,12 +21,12 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <include/core/SkImage.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
 #include <include/gpu/ganesh/SkImageGanesh.h>
 #include <include/gpu/ganesh/SkSurfaceGanesh.h>
 #include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
 #include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
-#include <include/gpu/vk/GrVkTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
 
 #include "skia/ColorSpaces.h"
 #include "skia/compat/SkiaBackendTexture.h"
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.h b/libs/renderengine/skia/compat/GaneshBackendTexture.h
index 5cf8647..4337df1 100644
--- a/libs/renderengine/skia/compat/GaneshBackendTexture.h
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.h
@@ -21,7 +21,7 @@
 
 #include <include/android/GrAHardwareBufferUtils.h>
 #include <include/core/SkColorSpace.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
 
 #include <android-base/macros.h>
 
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.cpp b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
index b121fe8..931f843 100644
--- a/libs/renderengine/skia/compat/GaneshGpuContext.cpp
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
@@ -19,12 +19,12 @@
 #include <include/core/SkImageInfo.h>
 #include <include/core/SkSurface.h>
 #include <include/core/SkTraceMemoryDump.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/GrTypes.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrTypes.h>
 #include <include/gpu/ganesh/SkSurfaceGanesh.h>
 #include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
 #include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <include/gpu/gl/GrGLInterface.h>
 #include <include/gpu/vk/VulkanBackendContext.h>
 
 #include "../AutoBackendTexture.h"
diff --git a/libs/renderengine/skia/compat/SkiaBackendTexture.h b/libs/renderengine/skia/compat/SkiaBackendTexture.h
index 09877a5..fa12624 100644
--- a/libs/renderengine/skia/compat/SkiaBackendTexture.h
+++ b/libs/renderengine/skia/compat/SkiaBackendTexture.h
@@ -18,7 +18,7 @@
 
 #include <include/android/GrAHardwareBufferUtils.h>
 #include <include/core/SkColorSpace.h>
-#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
 
 #include <android/hardware_buffer.h>
 #include <ui/GraphicTypes.h>
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
index 9fa6fb8..0bd8283 100644
--- a/libs/renderengine/skia/compat/SkiaGpuContext.h
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -20,10 +20,10 @@
 #define LOG_TAG "RenderEngine"
 
 #include <include/core/SkSurface.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/gl/GrGLInterface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
 #include <include/gpu/graphite/Context.h>
-#include "include/gpu/vk/VulkanBackendContext.h"
+#include <include/gpu/vk/VulkanBackendContext.h>
 
 #include "SkiaBackendTexture.h"
 
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index d3b3a73..22c196e 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -90,6 +90,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "liblog",
         "libutils",
         "server_configurable_flags",
diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp
index ca13afc..4757bdb 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -17,6 +17,10 @@
 
 #include <cstring>
 
+#include <android-base/parsedouble.h>
+#include <android-base/properties.h>
+#include <android-base/thread_annotations.h>
+
 #include <android_os_vibrator.h>
 
 #include <algorithm>
@@ -34,6 +38,21 @@
 static constexpr float SCALE_GAMMA = 0.65f; // Same as VibrationEffect.SCALE_GAMMA
 static constexpr float SCALE_LEVEL_GAIN = 1.4f; // Same as VibrationConfig.DEFAULT_SCALE_LEVEL_GAIN
 
+float getScaleLevelGain() {
+    static std::mutex gMutex;
+    static float gScaleLevelGain GUARDED_BY(gMutex) = 0;
+    std::lock_guard lock(gMutex);
+    if (gScaleLevelGain != 0) {
+        return gScaleLevelGain;
+    }
+    float scaleGain;
+    std::string value = ::android::base::GetProperty("vendor.vibrator.scale.level.gain", "");
+    if (value.empty() || !::android::base::ParseFloat(value, &scaleGain) || scaleGain <= 1) {
+        scaleGain = SCALE_LEVEL_GAIN;
+    }
+    return gScaleLevelGain = scaleGain;
+}
+
 float getOldHapticScaleGamma(HapticLevel level) {
     switch (level) {
     case HapticLevel::VERY_LOW:
@@ -79,7 +98,8 @@
             case HapticLevel::NONE:
                 return 1.0f;
             default:
-                float scaleFactor = powf(SCALE_LEVEL_GAIN, static_cast<int32_t>(level));
+                float scaleLevelGain = getScaleLevelGain();
+                float scaleFactor = powf(scaleLevelGain, static_cast<int32_t>(level));
                 if (scaleFactor <= 0) {
                     ALOGE("Invalid scale factor %.2f for level %d, using fallback to 1.0",
                           scaleFactor, static_cast<int32_t>(level));
diff --git a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
index 9369f80..e817263 100644
--- a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
+++ b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/properties.h>
 #include <android_os_vibrator.h>
 #include <flag_macros.h>
 #include <gtest/gtest.h>
@@ -170,6 +171,12 @@
         ExternalVibrationUtilsTest, TestScaleV2ToHapticLevel,
         // Value of fix_audio_coupled_haptics_scaling is not important, should work with either
         REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
+    // Skip test on devices with custom scale level gain configured.
+    if (!::android::base::GetProperty("vendor.vibrator.scale.level.gain", "").empty()) {
+        GTEST_SKIP() << "system property for scale level gain is set, skip tests based on level";
+        return;
+    }
+
     float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 1, -1, 0.8f, -0.38f };
     scaleBuffer(HapticLevel::VERY_HIGH);
     EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
@@ -191,6 +198,12 @@
         ExternalVibrationUtilsTest, TestScaleV2ToScaleFactorUndefinedUsesHapticLevel,
         // Value of fix_audio_coupled_haptics_scaling is not important, should work with either
         REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
+    // Skip test on devices with custom scale level gain configured.
+    if (!::android::base::GetProperty("vendor.vibrator.scale.level.gain", "").empty()) {
+        GTEST_SKIP() << "system property for scale level gain is set, skip tests based on level";
+        return;
+    }
+
     constexpr float adaptiveScaleNone = 1.0f;
     float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8f, -0.38f};
     scaleBuffer(HapticScale(HapticLevel::VERY_HIGH, -1.0f /* scaleFactor */, adaptiveScaleNone));
@@ -238,7 +251,7 @@
     EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Haptic level scale up then adaptive scale down
-    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.13f };
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.16f, -0.13f};
     scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
     EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
@@ -276,7 +289,7 @@
     EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Haptic level scale up then adaptive scale down
-    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.07f };
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.16f, -0.07f};
     scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
     EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
@@ -300,8 +313,8 @@
         ExternalVibrationUtilsTest, TestAdaptiveScaleFactorUndefinedIgnoredScaleV2,
         // Value of fix_audio_coupled_haptics_scaling is not important, should work with either
         REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
-    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8f, -0.38f};
-    scaleBuffer(HapticLevel::VERY_HIGH, -1.0f /* adaptiveScaleFactor */);
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8, -0.38f};
+    scaleBuffer(HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, -1 /* adaptiveScaleFactor */));
     EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 }
 
@@ -312,27 +325,30 @@
     // Adaptive scale mutes vibration
     float expectedMuted[TEST_BUFFER_LENGTH];
     std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0);
-    scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */);
+    scaleBuffer(HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 0 /* adaptiveScaleFactor */));
     EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Haptic level scale up then adaptive scale down
-    float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.15f, -0.07f };
-    scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */);
+    float expectedVeryHigh[TEST_BUFFER_LENGTH] = {0.2f, -0.2f, 0.16f, -0.07f};
+    scaleBuffer(
+            HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 0.2f /* adaptiveScaleFactor */));
     EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Haptic level scale up then adaptive scale up
-    float expectedHigh[TEST_BUFFER_LENGTH] = { 1.5f, -1.5f, 0.95f, -0.41f };
-    scaleBuffer(HapticLevel::HIGH, 1.5f /* adaptiveScaleFactor */);
+    float expectedHigh[TEST_BUFFER_LENGTH] = {1.5f, -1.5f, 1.2f, -0.57f};
+    scaleBuffer(
+            HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 1.5f /* adaptiveScaleFactor */));
     EXPECT_FLOATS_NEARLY_EQ(expectedHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Haptic level scale down then adaptive scale down
-    float expectedLow[TEST_BUFFER_LENGTH] = { 0.42f, -0.42f, 0.21f, -0.08f };
-    scaleBuffer(HapticLevel::LOW, 0.6f /* adaptiveScaleFactor */);
+    float expectedLow[TEST_BUFFER_LENGTH] = {0.3f, -0.3f, 0.15f, -0.06f};
+    scaleBuffer(
+            HapticScale(HapticLevel::LOW, 0.5f /* scaleFactor */, 0.6f /* adaptiveScaleFactor */));
     EXPECT_FLOATS_NEARLY_EQ(expectedLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Haptic level scale down then adaptive scale up
-    float expectedVeryLow[TEST_BUFFER_LENGTH] = { 1.02f, -1.02f, 0.51f, -0.2f };
-    scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */);
+    float expectedVeryLow[TEST_BUFFER_LENGTH] = {1.0f, -1.0f, 0.51f, -0.2f};
+    scaleBuffer(HapticScale(HapticLevel::LOW, 0.5f /* scaleFactor */, 2 /* adaptiveScaleFactor */));
     EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 }
 
@@ -370,11 +386,13 @@
         REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) {
     // Scaled = { 0.2, -0.2, 0.15f, -0.07f };
     float expectedClippedVeryHigh[TEST_BUFFER_LENGTH] = { 0.15f, -0.15f, 0.15f, -0.07f };
-    scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */, 0.15f /* limit */);
+    scaleBuffer(HapticScale(HapticLevel::HIGH, 2 /* scaleFactor */, 0.2f /* adaptiveScaleFactor */),
+                0.15f /* limit */);
     EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 
     // Scaled = { 1.02f, -1.02f, 0.51f, -0.2f }
     float expectedClippedVeryLow[TEST_BUFFER_LENGTH] = { 0.7f, -0.7f, 0.51f, -0.2f };
-    scaleBuffer(HapticLevel::VERY_LOW, 2 /* adaptiveScaleFactor */, 0.7f /* limit */);
+    scaleBuffer(HapticScale(HapticLevel::LOW, 0.5 /* scaleFactor */, 2 /* adaptiveScaleFactor */),
+                0.7f /* limit */);
     EXPECT_FLOATS_NEARLY_EQ(expectedClippedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE);
 }
diff --git a/opengl/OWNERS b/opengl/OWNERS
index 3d60a1d..645a578 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -2,5 +2,4 @@
 cnorthrop@google.com
 ianelliott@google.com
 jessehall@google.com
-lpy@google.com
-vantablack@google.com
+tomnom@google.com
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 16de390..5159ffe 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -40,9 +40,6 @@
     symbol_file: "libEGL.map.txt",
     first_version: "9",
     unversioned_until: "current",
-    export_header_libs: [
-        "libEGL_headers",
-    ],
 }
 
 ndk_library {
@@ -50,9 +47,6 @@
     symbol_file: "libGLESv1_CM.map.txt",
     first_version: "9",
     unversioned_until: "current",
-    export_header_libs: [
-        "libGLESv1_CM_headers",
-    ],
 }
 
 ndk_library {
@@ -60,9 +54,6 @@
     symbol_file: "libGLESv2.map.txt",
     first_version: "9",
     unversioned_until: "current",
-    export_header_libs: [
-        "libGLESv2_headers",
-    ],
 }
 
 ndk_library {
@@ -70,9 +61,6 @@
     symbol_file: "libGLESv3.map.txt",
     first_version: "18",
     unversioned_until: "current",
-    export_header_libs: [
-        "libGLESv3_headers",
-    ],
 }
 
 cc_defaults {
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index 00161e6..7628745 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -44,7 +44,7 @@
 
 #include "gpuwork/gpuWork.h"
 
-#define ONE_MS_IN_NS (10000000)
+#define MSEC_PER_NSEC (1000LU * 1000LU)
 
 namespace android {
 namespace gpuwork {
@@ -385,10 +385,11 @@
     ALOGI("pullWorkAtoms: after random selection: uids.size() == %zu", uids.size());
 
     auto now = std::chrono::steady_clock::now();
-    long long duration =
-            std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
-                    .count();
-    if (duration > std::numeric_limits<int32_t>::max() || duration < 0) {
+    int32_t duration =
+            static_cast<int32_t>(
+                std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
+                    .count());
+    if (duration < 0) {
         // This is essentially impossible. If it does somehow happen, give up,
         // but still clear the map.
         clearMap();
@@ -404,13 +405,14 @@
             }
             const UidTrackingInfo& info = it->second;
 
-            uint64_t total_active_duration_ms = info.total_active_duration_ns / ONE_MS_IN_NS;
-            uint64_t total_inactive_duration_ms = info.total_inactive_duration_ns / ONE_MS_IN_NS;
+            int32_t total_active_duration_ms =
+                static_cast<int32_t>(info.total_active_duration_ns / MSEC_PER_NSEC);
+            int32_t total_inactive_duration_ms =
+                static_cast<int32_t>(info.total_inactive_duration_ns / MSEC_PER_NSEC);
 
             // Skip this atom if any numbers are out of range. |duration| is
             // already checked above.
-            if (total_active_duration_ms > std::numeric_limits<int32_t>::max() ||
-                total_inactive_duration_ms > std::numeric_limits<int32_t>::max()) {
+            if (total_active_duration_ms < 0 || total_inactive_duration_ms < 0) {
                 continue;
             }
 
@@ -421,11 +423,11 @@
                                           // gpu_id
                                           bitcast_int32(gpuId),
                                           // time_duration_seconds
-                                          static_cast<int32_t>(duration),
+                                          duration,
                                           // total_active_duration_millis
-                                          static_cast<int32_t>(total_active_duration_ms),
+                                          total_active_duration_ms,
                                           // total_inactive_duration_millis
-                                          static_cast<int32_t>(total_inactive_duration_ms));
+                                          total_inactive_duration_ms);
         }
     }
     clearMap();
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
index e70da54..60cd2c7 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -125,7 +125,7 @@
     static constexpr size_t kNumGpusHardLimit = 32;
 
     // The minimum GPU time needed to actually log stats for a UID.
-    static constexpr uint64_t kMinGpuTimeNanoseconds = 30U * 1000000000U; // 30 seconds.
+    static constexpr uint64_t kMinGpuTimeNanoseconds = 10LLU * 1000000000LLU; // 10 seconds.
 
     // The previous time point at which |mGpuWorkMap| was cleared.
     std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex);
diff --git a/services/inputflinger/InputFilter.cpp b/services/inputflinger/InputFilter.cpp
index 2d5803b..2ef94fb 100644
--- a/services/inputflinger/InputFilter.cpp
+++ b/services/inputflinger/InputFilter.cpp
@@ -146,6 +146,12 @@
 
 void InputFilter::dump(std::string& dump) {
     dump += "InputFilter:\n";
+    if (isFilterEnabled()) {
+        std::string result;
+        LOG_ALWAYS_FATAL_IF(!mInputFilterRust->dumpFilter(&result).isOk());
+        dump += result;
+        dump += "\n";
+    }
 }
 
 } // namespace android
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 41e5247..b155122 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -250,6 +250,10 @@
         mCollector->dump(dump);
         dump += '\n';
     }
+    if (ENABLE_INPUT_FILTER_RUST) {
+        mInputFilter->dump(dump);
+        dump += '\n';
+    }
     mDispatcher->dump(dump);
     dump += '\n';
 }
diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
index 994d1c4..31b7231 100644
--- a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
+++ b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl
@@ -54,5 +54,7 @@
 
     /** Notifies when configuration changes */
     void notifyConfigurationChanged(in InputFilterConfiguration config);
+
+    String dumpFilter();
 }
 
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index dd46bbc..c8e7790 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -20,19 +20,14 @@
 #include <sstream>
 
 #include <android-base/stringprintf.h>
-#include <com_android_input_flags.h>
 #include <input/PrintTools.h>
 #include <linux/input-event-codes.h>
 #include <log/log_main.h>
 
-namespace input_flags = com::android::input::flags;
-
 namespace android {
 
 namespace {
 
-static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
-
 int32_t actionWithIndex(int32_t action, int32_t index) {
     return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 }
@@ -48,12 +43,6 @@
     return i;
 }
 
-void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
-                       RawAbsoluteAxisInfo& evdevAxis) {
-    deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue,
-                              evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution);
-}
-
 } // namespace
 
 CapturedTouchpadEventConverter::CapturedTouchpadEventConverter(
@@ -119,15 +108,8 @@
 }
 
 void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
-    if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
-        tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
-                                         AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
-        tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
-                                         AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
-    } else {
-        tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
-        tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
-    }
+    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
+    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
     tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
     tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
     tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
@@ -153,23 +135,8 @@
                                                           int32_t evdevAxis) const {
     std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
     if (info) {
-        addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info);
-    }
-}
-
-void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo,
-                                                                      int32_t androidAxis,
-                                                                      int32_t androidRelativeAxis,
-                                                                      int32_t evdevAxis) const {
-    std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
-    if (axisInfo) {
-        addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo);
-
-        // The largest movement we could possibly report on a relative axis is from the minimum to
-        // the maximum (or vice versa) of the absolute axis.
-        float range = axisInfo->maxValue - axisInfo->minValue;
-        deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat,
-                                  axisInfo->fuzz, axisInfo->resolution);
+        deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat,
+                                  info->fuzz, info->resolution);
     }
 }
 
@@ -196,7 +163,7 @@
     std::list<NotifyArgs> out;
     std::vector<PointerCoords> coords;
     std::vector<PointerProperties> properties;
-    std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber;
+    std::map<size_t, size_t> coordsIndexForSlotNumber;
 
     // For all the touches that were already down, send a MOVE event with their updated coordinates.
     // A convention of the MotionEvent API is that pointer coordinates in UP events match the
@@ -208,19 +175,11 @@
             // to stay perfectly still between frames, and if it does the worst that can happen is
             // an extra MOVE event, so it's not worth the overhead of checking for changes.
             coordsIndexForSlotNumber[slotNumber] = coords.size();
-            coords.push_back(makePointerCoordsForSlot(slotNumber));
+            coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
             properties.push_back({.id = pointerId, .toolType = ToolType::FINGER});
         }
         out.push_back(
                 makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
-        if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
-            // For any further events we send from this sync, the pointers won't have moved relative
-            // to the positions we just reported in this MOVE event, so zero out the relative axes.
-            for (PointerCoords& pointer : coords) {
-                pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
-                pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
-            }
-        }
     }
 
     std::vector<size_t> upSlots, downSlots;
@@ -275,9 +234,6 @@
                                      /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));
 
         freePointerIdForSlot(slotNumber);
-        if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
-            mPreviousCoordsForSlotNumber.erase(slotNumber);
-        }
         coords.erase(coords.begin() + indexToRemove);
         properties.erase(properties.begin() + indexToRemove);
         // Now that we've removed some coords and properties, we might have to update the slot
@@ -298,7 +254,7 @@
                 : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex);
 
         coordsIndexForSlotNumber[slotNumber] = coordsIndex;
-        coords.push_back(makePointerCoordsForSlot(slotNumber));
+        coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
         properties.push_back(
                 {.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER});
 
@@ -330,22 +286,12 @@
                             AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{});
 }
 
-PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) {
-    const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber);
+PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(
+        const MultiTouchMotionAccumulator::Slot& slot) const {
     PointerCoords coords;
     coords.clear();
     coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
-    if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
-        if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
-            it != mPreviousCoordsForSlotNumber.end()) {
-            auto [oldX, oldY] = it->second;
-            coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
-            coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
-        }
-        mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
-    }
-
     coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
     coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
     coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor());
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
index d6c0708..9b6df7a 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
@@ -21,7 +21,6 @@
 #include <map>
 #include <set>
 #include <string>
-#include <utility>
 #include <vector>
 
 #include <android/input.h>
@@ -50,14 +49,12 @@
 private:
     void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
                               int32_t evdevAxis) const;
-    void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis,
-                                          int32_t androidRelativeAxis, int32_t evdevAxis) const;
     [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
     [[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
                                                   const std::vector<PointerCoords>& coords,
                                                   const std::vector<PointerProperties>& properties,
                                                   int32_t actionButton = 0, int32_t flags = 0);
-    PointerCoords makePointerCoordsForSlot(size_t slotNumber);
+    PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
     int32_t allocatePointerIdToSlot(size_t slotNumber);
     void freePointerIdForSlot(size_t slotNumber);
 
@@ -79,7 +76,8 @@
 
     std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse;
     std::map<size_t, int32_t> mPointerIdForSlotNumber;
-    std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber;
+
+    static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index dbc2872..b17e79a 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -425,7 +425,7 @@
     std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
     if (state) {
         if (mTouchpadHardwareStateNotificationsEnabled) {
-            getPolicy()->notifyTouchpadHardwareState(*state, rawEvent.deviceId);
+            getPolicy()->notifyTouchpadHardwareState(*state, getDeviceId());
         }
         updatePalmDetectionMetrics();
         return sendHardwareState(rawEvent.when, rawEvent.readTime, *state);
diff --git a/services/inputflinger/rust/bounce_keys_filter.rs b/services/inputflinger/rust/bounce_keys_filter.rs
index dc4f1df..e05e8e5 100644
--- a/services/inputflinger/rust/bounce_keys_filter.rs
+++ b/services/inputflinger/rust/bounce_keys_filter.rs
@@ -65,7 +65,10 @@
 
 impl Filter for BounceKeysFilter {
     fn notify_key(&mut self, event: &KeyEvent) {
-        if !(self.supported_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) {
+        // Check if it is a supported device and event source contains Source::KEYBOARD
+        if !(self.supported_devices.contains(&event.deviceId)
+            && event.source.0 & Source::KEYBOARD.0 != 0)
+        {
             self.next.notify_key(event);
             return;
         }
@@ -130,6 +133,15 @@
     fn destroy(&mut self) {
         self.next.destroy();
     }
+
+    fn dump(&mut self, dump_str: String) -> String {
+        let mut result = "Bounce Keys filter: \n".to_string();
+        result += &format!("\tthreshold = {:?}ns\n", self.bounce_key_threshold_ns);
+        result += &format!("\tkey_event_map = {:?}\n", self.key_event_map);
+        result += &format!("\tblocked_events = {:?}\n", self.blocked_events);
+        result += &format!("\tsupported_devices = {:?}\n", self.supported_devices);
+        self.next.dump(dump_str + &result)
+    }
 }
 
 #[cfg(test)]
@@ -191,6 +203,41 @@
     }
 
     #[test]
+    fn test_is_notify_key_for_tv_remote() {
+        let mut next = TestFilter::new();
+        let mut filter = setup_filter_with_external_device(
+            Box::new(next.clone()),
+            1,   /* device_id */
+            100, /* threshold */
+            KeyboardType::NonAlphabetic,
+        );
+
+        let source = Source(Source::KEYBOARD.0 | Source::DPAD.0);
+        let event = KeyEvent { action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event = KeyEvent { action: KeyEventAction::UP, source, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        next.clear();
+        let event = KeyEvent { action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert!(next.last_event().is_none());
+
+        let event =
+            KeyEvent { eventTime: 100, action: KeyEventAction::UP, source, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert!(next.last_event().is_none());
+
+        let event =
+            KeyEvent { eventTime: 200, action: KeyEventAction::DOWN, source, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+    }
+
+    #[test]
     fn test_is_notify_key_blocks_for_internal_keyboard() {
         let mut next = TestFilter::new();
         let mut filter = setup_filter_with_internal_device(
diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs
index f166723..e221244 100644
--- a/services/inputflinger/rust/input_filter.rs
+++ b/services/inputflinger/rust/input_filter.rs
@@ -43,6 +43,7 @@
     fn notify_key(&mut self, event: &KeyEvent);
     fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]);
     fn destroy(&mut self);
+    fn dump(&mut self, dump_str: String) -> String;
 }
 
 struct InputFilterState {
@@ -122,18 +123,30 @@
                     self.input_filter_thread.clone(),
                 ));
                 state.enabled = true;
-                info!("Slow keys filter is installed");
+                info!(
+                    "Slow keys filter is installed, threshold = {:?}ns",
+                    config.slowKeysThresholdNs
+                );
             }
             if config.bounceKeysThresholdNs > 0 {
                 first_filter =
                     Box::new(BounceKeysFilter::new(first_filter, config.bounceKeysThresholdNs));
                 state.enabled = true;
-                info!("Bounce keys filter is installed");
+                info!(
+                    "Bounce keys filter is installed, threshold = {:?}ns",
+                    config.bounceKeysThresholdNs
+                );
             }
             state.first_filter = first_filter;
         }
         Result::Ok(())
     }
+
+    fn dumpFilter(&self) -> binder::Result<String> {
+        let first_filter = &mut self.state.lock().unwrap().first_filter;
+        let dump_str = first_filter.dump(String::new());
+        Result::Ok(dump_str)
+    }
 }
 
 struct BaseFilter {
@@ -161,6 +174,11 @@
     fn destroy(&mut self) {
         // do nothing
     }
+
+    fn dump(&mut self, dump_str: String) -> String {
+        // do nothing
+        dump_str
+    }
 }
 
 /// This struct wraps around IInputFilterCallbacks restricting access to only
@@ -397,6 +415,10 @@
         fn destroy(&mut self) {
             self.inner().is_destroy_called = true;
         }
+        fn dump(&mut self, dump_str: String) -> String {
+            // do nothing
+            dump_str
+        }
     }
 }
 
diff --git a/services/inputflinger/rust/slow_keys_filter.rs b/services/inputflinger/rust/slow_keys_filter.rs
index 3e242d8..8830aac 100644
--- a/services/inputflinger/rust/slow_keys_filter.rs
+++ b/services/inputflinger/rust/slow_keys_filter.rs
@@ -100,7 +100,7 @@
             // acquire write lock
             let mut slow_filter = self.write_inner();
             if !(slow_filter.supported_devices.contains(&event.deviceId)
-                && event.source == Source::KEYBOARD)
+                && event.source.0 & Source::KEYBOARD.0 != 0)
             {
                 slow_filter.next.notify_key(event);
                 return;
@@ -186,6 +186,16 @@
         slow_filter.input_filter_thread.unregister_thread_callback(Box::new(self.clone()));
         slow_filter.next.destroy();
     }
+
+    fn dump(&mut self, dump_str: String) -> String {
+        let mut slow_filter = self.write_inner();
+        let mut result = "Slow Keys filter: \n".to_string();
+        result += &format!("\tthreshold = {:?}ns\n", slow_filter.slow_key_threshold_ns);
+        result += &format!("\tongoing_down_events = {:?}\n", slow_filter.ongoing_down_events);
+        result += &format!("\tpending_down_events = {:?}\n", slow_filter.pending_down_events);
+        result += &format!("\tsupported_devices = {:?}\n", slow_filter.supported_devices);
+        slow_filter.next.dump(dump_str + &result)
+    }
 }
 
 impl ThreadCallback for SlowKeysFilter {
@@ -286,6 +296,63 @@
     }
 
     #[test]
+    fn test_notify_key_for_tv_remote_when_key_pressed_for_threshold_time() {
+        let test_callbacks = TestCallbacks::new();
+        let test_thread = get_thread(test_callbacks.clone());
+        let next = TestFilter::new();
+        let mut filter = setup_filter_with_external_device(
+            Box::new(next.clone()),
+            test_thread.clone(),
+            1, /* device_id */
+            SLOW_KEYS_THRESHOLD_NS,
+            KeyboardType::NonAlphabetic,
+        );
+        let down_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+        let source = Source(Source::KEYBOARD.0 | Source::DPAD.0);
+        filter.notify_key(&KeyEvent {
+            action: KeyEventAction::DOWN,
+            downTime: down_time,
+            eventTime: down_time,
+            source,
+            ..BASE_KEY_EVENT
+        });
+        assert!(next.last_event().is_none());
+
+        std::thread::sleep(Duration::from_nanos(2 * SLOW_KEYS_THRESHOLD_NS as u64));
+        assert_eq!(
+            next.last_event().unwrap(),
+            KeyEvent {
+                action: KeyEventAction::DOWN,
+                downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+                eventTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+                source,
+                policyFlags: POLICY_FLAG_DISABLE_KEY_REPEAT,
+                ..BASE_KEY_EVENT
+            }
+        );
+
+        let up_time = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_nanoseconds();
+        filter.notify_key(&KeyEvent {
+            action: KeyEventAction::UP,
+            downTime: down_time,
+            eventTime: up_time,
+            source,
+            ..BASE_KEY_EVENT
+        });
+
+        assert_eq!(
+            next.last_event().unwrap(),
+            KeyEvent {
+                action: KeyEventAction::UP,
+                downTime: down_time + SLOW_KEYS_THRESHOLD_NS,
+                eventTime: up_time,
+                source,
+                ..BASE_KEY_EVENT
+            }
+        );
+    }
+
+    #[test]
     fn test_notify_key_for_internal_alphabetic_keyboard_when_key_pressed_for_threshold_time() {
         let test_callbacks = TestCallbacks::new();
         let test_thread = get_thread(test_callbacks.clone());
diff --git a/services/inputflinger/rust/sticky_keys_filter.rs b/services/inputflinger/rust/sticky_keys_filter.rs
index dfcea79..161a5fc 100644
--- a/services/inputflinger/rust/sticky_keys_filter.rs
+++ b/services/inputflinger/rust/sticky_keys_filter.rs
@@ -134,6 +134,14 @@
     fn destroy(&mut self) {
         self.next.destroy();
     }
+
+    fn dump(&mut self, dump_str: String) -> String {
+        let mut result = "Sticky Keys filter: \n".to_string();
+        result += &format!("\tmodifier_state = {:?}\n", self.modifier_state);
+        result += &format!("\tlocked_modifier_state = {:?}\n", self.locked_modifier_state);
+        result += &format!("\tcontributing_devices = {:?}\n", self.contributing_devices);
+        self.next.dump(dump_str + &result)
+    }
 }
 
 fn is_modifier_key(keycode: i32) -> bool {
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index d39ad3f..f20c43c 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -20,7 +20,6 @@
 #include <memory>
 
 #include <EventHub.h>
-#include <com_android_input_flags.h>
 #include <gtest/gtest.h>
 #include <linux/input-event-codes.h>
 #include <linux/input.h>
@@ -33,8 +32,6 @@
 #include "TestEventMatchers.h"
 #include "TestInputListener.h"
 
-namespace input_flags = com::android::input::flags;
-
 namespace android {
 
 using testing::AllOf;
@@ -50,8 +47,6 @@
             mReader(mFakeEventHub, mFakePolicy, mFakeListener),
             mDevice(newDevice()),
             mDeviceContext(*mDevice, EVENTHUB_ID) {
-        input_flags::include_relative_axis_values_for_captured_touchpads(true);
-
         const size_t slotCount = 8;
         mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0);
         mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true);
@@ -131,7 +126,7 @@
 
 TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) {
     mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45);
-    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40);
     mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35);
     mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30);
     mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25);
@@ -155,8 +150,8 @@
     const InputDeviceInfo::MotionRange* posY =
             info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD);
     ASSERT_NE(nullptr, posY);
-    EXPECT_NEAR(-500, posY->min, EPSILON);
-    EXPECT_NEAR(2000, posY->max, EPSILON);
+    EXPECT_NEAR(0, posY->min, EPSILON);
+    EXPECT_NEAR(2500, posY->max, EPSILON);
     EXPECT_NEAR(40, posY->resolution, EPSILON);
 
     const InputDeviceInfo::MotionRange* touchMajor =
@@ -187,22 +182,8 @@
     EXPECT_NEAR(800, toolMinor->max, EPSILON);
     EXPECT_NEAR(20, toolMinor->resolution, EPSILON);
 
-    // ...except for the relative motion axes, derived from the corresponding absolute ones:
-    const InputDeviceInfo::MotionRange* relX =
-            info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD);
-    ASSERT_NE(nullptr, relX);
-    EXPECT_NEAR(-4000, relX->min, EPSILON);
-    EXPECT_NEAR(4000, relX->max, EPSILON);
-    EXPECT_NEAR(45, relX->resolution, EPSILON);
-
-    const InputDeviceInfo::MotionRange* relY =
-            info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD);
-    ASSERT_NE(nullptr, relY);
-    EXPECT_NEAR(-2500, relY->min, EPSILON);
-    EXPECT_NEAR(2500, relY->max, EPSILON);
-    EXPECT_NEAR(40, relY->resolution, EPSILON);
-
-    // ...orientation and pressure, which get scaled:
+    // ...except orientation and pressure, which get scaled, and size, which is generated from other
+    // values.
     const InputDeviceInfo::MotionRange* orientation =
             info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD);
     ASSERT_NE(nullptr, orientation);
@@ -217,7 +198,6 @@
     EXPECT_NEAR(1, pressure->max, EPSILON);
     EXPECT_NEAR(0, pressure->resolution, EPSILON);
 
-    // ... and size, which is generated from other values.
     const InputDeviceInfo::MotionRange* size =
             info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD);
     ASSERT_NE(nullptr, size);
@@ -239,9 +219,7 @@
     // present, since it's generated from axes that aren't provided by this device).
     EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD));
     EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD));
-    EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD));
-    EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD));
-    EXPECT_EQ(4u, info.getMotionRanges().size());
+    EXPECT_EQ(2u, info.getMotionRanges().size());
 }
 
 TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) {
@@ -257,16 +235,14 @@
 
     EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
-                      WithCoords(50, 100), WithRelativeMotion(0, 0),
-                      WithToolType(ToolType::FINGER)));
+                      WithCoords(50, 100), WithToolType(ToolType::FINGER)));
 
     processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
     processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99);
 
     EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
-                      WithCoords(52, 99), WithRelativeMotion(2, -1),
-                      WithToolType(ToolType::FINGER)));
+                      WithCoords(52, 99), WithToolType(ToolType::FINGER)));
 
     processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
     processAxis(conv, EV_KEY, BTN_TOUCH, 0);
@@ -279,9 +255,8 @@
                             VariantWith<NotifyMotionArgs>(
                                     WithMotionAction(AMOTION_EVENT_ACTION_UP))));
     EXPECT_THAT(args,
-                Each(VariantWith<NotifyMotionArgs>(
-                        AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u),
-                              WithToolType(ToolType::FINGER)))));
+                Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u),
+                                                         WithToolType(ToolType::FINGER)))));
 }
 
 TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) {
@@ -532,13 +507,13 @@
 
     EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
-                      WithCoords(51, 100), WithRelativeMotion(0, 0)));
+                      WithCoords(51, 100)));
 
     processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
 
     EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
-                      WithCoords(52, 100), WithRelativeMotion(1, 0)));
+                      WithCoords(52, 100)));
 }
 
 TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) {
@@ -578,7 +553,7 @@
 
     EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
-                      WithCoords(98, 148), WithRelativeMotion(-2, -2)));
+                      WithCoords(98, 148)));
 }
 
 TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) {
@@ -685,8 +660,7 @@
 
     EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
-                      WithCoords(50, 100), WithRelativeMotion(0, 0),
-                      WithToolType(ToolType::FINGER)));
+                      WithCoords(50, 100), WithToolType(ToolType::FINGER)));
 
     processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
     processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
@@ -704,16 +678,13 @@
                 ElementsAre(VariantWith<NotifyMotionArgs>(
                                     AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
                                           WithPointerCount(1u), WithCoords(52, 99),
-                                          WithRelativeMotion(2, -1),
                                           WithToolType(ToolType::FINGER))),
                             VariantWith<NotifyMotionArgs>(
                                     AllOf(WithMotionAction(
                                                   AMOTION_EVENT_ACTION_POINTER_DOWN |
                                                   1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                                           WithPointerCount(2u), WithPointerCoords(0, 52, 99),
-                                          WithPointerRelativeMotion(0, 0, 0),
                                           WithPointerCoords(1, 250, 200),
-                                          WithPointerRelativeMotion(1, 0, 0),
                                           WithPointerToolType(0, ToolType::FINGER),
                                           WithPointerToolType(1, ToolType::FINGER)))));
 
@@ -729,17 +700,14 @@
     std::list<NotifyArgs> args = processSync(conv);
     EXPECT_THAT(args,
                 ElementsAre(VariantWith<NotifyMotionArgs>(
-                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
-                                          WithPointerRelativeMotion(1, 5, 2))),
-                            VariantWith<NotifyMotionArgs>(
-                                    AllOf(WithMotionAction(
-                                                  AMOTION_EVENT_ACTION_POINTER_UP |
-                                                  0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-                                          WithPointerRelativeMotion(1, 0, 0)))));
+                                    WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+                            VariantWith<NotifyMotionArgs>(WithMotionAction(
+                                    AMOTION_EVENT_ACTION_POINTER_UP |
+                                    0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT))));
     EXPECT_THAT(args,
                 Each(VariantWith<NotifyMotionArgs>(
                         AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99),
-                              WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202),
+                              WithPointerCoords(1, 255, 202),
                               WithPointerToolType(1, ToolType::FINGER),
                               WithPointerToolType(0, ToolType::FINGER)))));
 
@@ -755,69 +723,9 @@
                                     WithMotionAction(AMOTION_EVENT_ACTION_UP))));
     EXPECT_THAT(args,
                 Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202),
-                                                         WithPointerRelativeMotion(1, 0, 0),
                                                          WithToolType(ToolType::FINGER)))));
 }
 
-TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) {
-    CapturedTouchpadEventConverter conv = createConverter();
-    // Put down one finger.
-    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
-    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
-
-    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
-    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
-
-    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
-                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
-                      WithCoords(50, 100), WithRelativeMotion(0, 0)));
-
-    // Move it in negative X and Y directions.
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47);
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97);
-
-    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
-                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97),
-                      WithRelativeMotion(-3, -3)));
-
-    // Lift it.
-    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
-    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
-    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
-
-    std::list<NotifyArgs> args = processSync(conv);
-    EXPECT_THAT(args,
-                ElementsAre(VariantWith<NotifyMotionArgs>(
-                                    WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
-                            VariantWith<NotifyMotionArgs>(
-                                    WithMotionAction(AMOTION_EVENT_ACTION_UP))));
-    EXPECT_THAT(args,
-                Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97),
-                                                         WithRelativeMotion(0, 0),
-                                                         WithPointerCount(1u)))));
-
-    // Put down another finger using the same slot. Relative axis values should be cleared.
-    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60);
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60);
-
-    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
-    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
-
-    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
-                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
-                      WithCoords(60, 60), WithRelativeMotion(0, 0)));
-
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64);
-    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58);
-
-    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
-                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
-                      WithCoords(64, 58), WithRelativeMotion(4, -2)));
-}
-
 // Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out.
 TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) {
     CapturedTouchpadEventConverter conv = createConverter();
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index d77d539..e1f844c 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -32,19 +32,23 @@
 } // namespace
 
 void FakeInputReaderPolicy::assertInputDevicesChanged() {
-    waitForInputDevices([](bool devicesChanged) {
-        if (!devicesChanged) {
-            FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
-        }
-    });
+    waitForInputDevices(
+            [](bool devicesChanged) {
+                if (!devicesChanged) {
+                    FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
+                }
+            },
+            ADD_INPUT_DEVICE_TIMEOUT);
 }
 
 void FakeInputReaderPolicy::assertInputDevicesNotChanged() {
-    waitForInputDevices([](bool devicesChanged) {
-        if (devicesChanged) {
-            FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
-        }
-    });
+    waitForInputDevices(
+            [](bool devicesChanged) {
+                if (devicesChanged) {
+                    FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
+                }
+            },
+            INPUT_DEVICES_DIDNT_CHANGE_TIMEOUT);
 }
 
 void FakeInputReaderPolicy::assertStylusGestureNotified(int32_t deviceId) {
@@ -261,13 +265,13 @@
     return "";
 }
 
-void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
+void FakeInputReaderPolicy::waitForInputDevices(std::function<void(bool)> processDevicesChanged,
+                                                std::chrono::milliseconds timeout) {
     std::unique_lock<std::mutex> lock(mLock);
     base::ScopedLockAssertion assumeLocked(mLock);
 
     const bool devicesChanged =
-            mDevicesChangedCondition.wait_for(lock,
-                                              ADD_INPUT_DEVICE_TIMEOUT * HW_TIMEOUT_MULTIPLIER,
+            mDevicesChangedCondition.wait_for(lock, timeout * HW_TIMEOUT_MULTIPLIER,
                                               [this]() REQUIRES(mLock) {
                                                   return mInputDevicesChanged;
                                               });
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h
index e5ba620..61bb9fc 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.h
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.h
@@ -88,7 +88,8 @@
     std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
             const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override;
     std::string getDeviceAlias(const InputDeviceIdentifier&) override;
-    void waitForInputDevices(std::function<void(bool)> processDevicesChanged);
+    void waitForInputDevices(std::function<void(bool)> processDevicesChanged,
+                             std::chrono::milliseconds timeout);
     void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
 
     mutable std::mutex mLock;
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index 082bbb8..d2337dd 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -25,7 +25,10 @@
 using std::chrono_literals::operator""ms;
 
 // Timeout for waiting for an input device to be added and processed
-static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 500ms;
+static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 5000ms;
+
+// Timeout for asserting that an input device change did not occur
+static constexpr std::chrono::duration INPUT_DEVICES_DIDNT_CHANGE_TIMEOUT = 100ms;
 
 // Timeout for waiting for an expected event
 static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index f3be041..cfedc6e 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -654,15 +654,6 @@
     return argX == x && argY == y;
 }
 
-MATCHER_P3(WithPointerRelativeMotion, pointer, x, y,
-           "InputEvent with specified relative motion for pointer") {
-    const auto argX = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
-    const auto argY = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
-    *result_listener << "expected pointer " << pointer << " to have relative motion (" << x << ", "
-                     << y << "), but got (" << argX << ", " << argY << ")";
-    return argX == x && argY == y;
-}
-
 MATCHER_P3(WithGestureOffset, dx, dy, epsilon,
            "InputEvent with specified touchpad gesture offset") {
     const auto argGestureX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3895ffe..57b473b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1583,7 +1583,11 @@
     // Only 4 modes supported for a SensorEventConnection ... NORMAL, DATA_INJECTION,
     // REPLAY_DATA_INJECTION and HAL_BYPASS_REPLAY_DATA_INJECTION
     if (requestedMode != NORMAL && !isInjectionMode(requestedMode)) {
-        return nullptr;
+      ALOGE(
+          "Failed to create sensor event connection: invalid request mode. "
+          "requestMode: %d",
+          requestedMode);
+      return nullptr;
     }
     resetTargetSdkVersionCache(opPackageName);
 
@@ -1591,8 +1595,19 @@
     // To create a client in DATA_INJECTION mode to inject data, SensorService should already be
     // operating in DI mode.
     if (requestedMode == DATA_INJECTION) {
-        if (mCurrentOperatingMode != DATA_INJECTION) return nullptr;
-        if (!isAllowListedPackage(packageName)) return nullptr;
+      if (mCurrentOperatingMode != DATA_INJECTION) {
+        ALOGE(
+            "Failed to create sensor event connection: sensor service not in "
+            "DI mode when creating a client in DATA_INJECTION mode");
+        return nullptr;
+      }
+      if (!isAllowListedPackage(packageName)) {
+        ALOGE(
+            "Failed to create sensor event connection: package %s not in "
+            "allowed list for DATA_INJECTION mode",
+            packageName.c_str());
+        return nullptr;
+      }
     }
 
     uid_t uid = IPCThreadState::self()->getCallingUid();
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 20ae74a..66237b9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -60,6 +60,7 @@
 using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
 using AidlHdrConversionCapability =
         aidl::android::hardware::graphics::common::HdrConversionCapability;
+using AidlHdcpLevels = aidl::android::hardware::drm::HdcpLevels;
 using AidlHdrConversionStrategy = aidl::android::hardware::graphics::common::HdrConversionStrategy;
 using AidlOverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties;
 using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
@@ -223,6 +224,12 @@
         return ::ndk::ScopedAStatus::ok();
     }
 
+    ::ndk::ScopedAStatus onHdcpLevelsChanged(int64_t in_display,
+                                             const AidlHdcpLevels& levels) override {
+        mCallback.onComposerHalHdcpLevelsChanged(translate<Display>(in_display), levels);
+        return ::ndk::ScopedAStatus::ok();
+    }
+
 private:
     HWC2::ComposerCallback& mCallback;
 };
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c2dc943..d426bca 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -67,6 +67,7 @@
 
 namespace hal = android::hardware::graphics::composer::hal;
 
+using aidl::android::hardware::drm::HdcpLevels;
 using aidl::android::hardware::graphics::common::DisplayHotplugEvent;
 using aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
 
@@ -85,6 +86,7 @@
     virtual void onComposerHalSeamlessPossible(hal::HWDisplayId) = 0;
     virtual void onComposerHalVsyncIdle(hal::HWDisplayId) = 0;
     virtual void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) = 0;
+    virtual void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) = 0;
 
 protected:
     ~ComposerCallback() = default;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 2a0ee5a..3736abc 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -697,6 +697,23 @@
         jd.jankType = mJankType;
         jd.frameIntervalNs =
                 (mRenderRate ? *mRenderRate : mDisplayFrameRenderRate).getPeriodNsecs();
+
+        if (mPredictionState == PredictionState::Valid) {
+            jd.scheduledAppFrameTimeNs = mPredictions.endTime - mPredictions.startTime;
+
+            // Using expected start, rather than actual, to measure the entire frame time. That is
+            // if the application starts the frame later than scheduled, include that delay in the
+            // frame time, as it usually means main thread being busy with non-rendering work.
+            if (mPresentState == PresentState::Dropped) {
+                jd.actualAppFrameTimeNs = mDropTime - mPredictions.startTime;
+            } else {
+                jd.actualAppFrameTimeNs = mActuals.endTime - mPredictions.startTime;
+            }
+        } else {
+            jd.scheduledAppFrameTimeNs = 0;
+            jd.actualAppFrameTimeNs = 0;
+        }
+
         JankTracker::onJankData(mLayerId, jd);
     }
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3c8af19..c8bb068 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -60,9 +60,7 @@
 #include <utils/StopWatch.h>
 
 #include <algorithm>
-#include <mutex>
 #include <optional>
-#include <sstream>
 
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWComposer.h"
@@ -72,7 +70,6 @@
 #include "FrontEnd/LayerHandle.h"
 #include "Layer.h"
 #include "LayerProtoHelper.h"
-#include "MutexUtils.h"
 #include "SurfaceFlinger.h"
 #include "TimeStats/TimeStats.h"
 #include "TransactionCallbackInvoker.h"
@@ -89,18 +86,6 @@
 
 const ui::Transform kIdentityTransform;
 
-ui::LogicalDisplayId toLogicalDisplayId(const ui::LayerStack& layerStack) {
-    return ui::LogicalDisplayId{static_cast<int32_t>(layerStack.id)};
-}
-
-bool assignTransform(ui::Transform* dst, ui::Transform& from) {
-    if (*dst == from) {
-        return false;
-    }
-    *dst = from;
-    return true;
-}
-
 TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
     using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
     using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
@@ -149,24 +134,11 @@
       : sequence(args.sequence),
         mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
         mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
-        mClientRef(args.client),
         mWindowType(static_cast<WindowInfo::Type>(
-                args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
-        mLayerCreationFlags(args.flags),
-        mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName, this)) {
+                args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))) {
     ALOGV("Creating Layer %s", getDebugName());
 
-    uint32_t layerFlags = 0;
-    if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
-    if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
-    if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
-    if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
-        layerFlags |= layer_state_t::eLayerSkipScreenshot;
-    mDrawingState.flags = layerFlags;
     mDrawingState.crop.makeInvalid();
-    mDrawingState.z = 0;
-    mDrawingState.color.a = 1.0f;
-    mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK;
     mDrawingState.sequence = 0;
     mDrawingState.transform.set(0, 0);
     mDrawingState.frameNumber = 0;
@@ -179,33 +151,9 @@
     mDrawingState.acquireFence = sp<Fence>::make(-1);
     mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
     mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
-    mDrawingState.hdrMetadata.validTypes = 0;
-    mDrawingState.surfaceDamageRegion = Region::INVALID_REGION;
-    mDrawingState.cornerRadius = 0.0f;
-    mDrawingState.backgroundBlurRadius = 0;
-    mDrawingState.api = -1;
-    mDrawingState.hasColorTransform = false;
-    mDrawingState.colorSpaceAgnostic = false;
-    mDrawingState.frameRateSelectionPriority = PRIORITY_UNSET;
     mDrawingState.metadata = args.metadata;
-    mDrawingState.shadowRadius = 0.f;
-    mDrawingState.fixedTransformHint = ui::Transform::ROT_INVALID;
     mDrawingState.frameTimelineInfo = {};
     mDrawingState.postTime = -1;
-    mDrawingState.destinationFrame.makeInvalid();
-    mDrawingState.isTrustedOverlay = false;
-    mDrawingState.dropInputMode = gui::DropInputMode::NONE;
-    mDrawingState.dimmingEnabled = true;
-    mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;
-    mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Propagate;
-
-    if (args.flags & ISurfaceComposerClient::eNoColorFill) {
-        // Set an invalid color so there is no color fill.
-        mDrawingState.color.r = -1.0_hf;
-        mDrawingState.color.g = -1.0_hf;
-        mDrawingState.color.b = -1.0_hf;
-    }
-
     mFrameTracker.setDisplayRefreshPeriod(
             args.flinger->mScheduler->getPacesetterVsyncPeriod().ns());
 
@@ -213,14 +161,9 @@
     mOwnerPid = args.ownerPid;
     mOwnerAppId = mOwnerUid % PER_USER_RANGE;
 
-    mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
     mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
-    mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
-
-    mSnapshot->sequence = sequence;
-    mSnapshot->name = getDebugName();
-    mSnapshot->premultipliedAlpha = mPremultipliedAlpha;
-    mSnapshot->parentTransform = {};
+    mLayerFEs.emplace_back(frontend::LayerHierarchy::TraversalPath{static_cast<uint32_t>(sequence)},
+                           args.flinger->getFactory().createLayerFE(mName, this));
 }
 
 void Layer::onFirstRef() {
@@ -253,35 +196,8 @@
 }
 
 // ---------------------------------------------------------------------------
-// callbacks
-// ---------------------------------------------------------------------------
-
-void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
-    if (mDrawingState.zOrderRelativeOf == nullptr) {
-        return;
-    }
-
-    sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
-    if (strongRelative == nullptr) {
-        setZOrderRelativeOf(nullptr);
-        return;
-    }
-
-    if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
-        strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
-        mFlinger->setTransactionFlags(eTraversalNeeded);
-        setZOrderRelativeOf(nullptr);
-    }
-}
-
-// ---------------------------------------------------------------------------
 // set-up
 // ---------------------------------------------------------------------------
-
-bool Layer::getPremultipledAlpha() const {
-    return mPremultipliedAlpha;
-}
-
 sp<IBinder> Layer::getHandle() {
     Mutex::Autolock _l(mLock);
     if (mGetHandleCalled) {
@@ -297,46 +213,6 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-static Rect reduce(const Rect& win, const Region& exclude) {
-    if (CC_LIKELY(exclude.isEmpty())) {
-        return win;
-    }
-    if (exclude.isRect()) {
-        return win.reduce(exclude.getBounds());
-    }
-    return Region(win).subtract(exclude).getBounds();
-}
-
-static FloatRect reduce(const FloatRect& win, const Region& exclude) {
-    if (CC_LIKELY(exclude.isEmpty())) {
-        return win;
-    }
-    // Convert through Rect (by rounding) for lack of FloatRegion
-    return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
-}
-
-Rect Layer::getScreenBounds(bool reduceTransparentRegion) const {
-    if (!reduceTransparentRegion) {
-        return Rect{mScreenBounds};
-    }
-
-    FloatRect bounds = getBounds();
-    ui::Transform t = getTransform();
-    // Transform to screen space.
-    bounds = t.transform(bounds);
-    return Rect{bounds};
-}
-
-FloatRect Layer::getBounds() const {
-    const State& s(getDrawingState());
-    return getBounds(getActiveTransparentRegion(s));
-}
-
-FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
-    // Subtract the transparent region and snap to the bounds.
-    return reduce(mBounds, activeTransparentRegion);
-}
-
 // No early returns.
 void Layer::updateTrustedPresentationState(const DisplayDevice* display,
                                            const frontend::LayerSnapshot* snapshot,
@@ -438,57 +314,6 @@
     return true;
 }
 
-void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform,
-                          float parentShadowRadius) {
-    const State& s(getDrawingState());
-
-    // Calculate effective layer transform
-    mEffectiveTransform = parentTransform * getActiveTransform(s);
-
-    if (CC_UNLIKELY(!isTransformValid())) {
-        ALOGW("Stop computing bounds for %s because it has invalid transformation.",
-              getDebugName());
-        return;
-    }
-
-    // Transform parent bounds to layer space
-    parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
-
-    // Calculate source bounds
-    mSourceBounds = computeSourceBounds(parentBounds);
-
-    // Calculate bounds by croping diplay frame with layer crop and parent bounds
-    FloatRect bounds = mSourceBounds;
-    const Rect layerCrop = getCrop(s);
-    if (!layerCrop.isEmpty()) {
-        bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
-    }
-    bounds = bounds.intersect(parentBounds);
-
-    mBounds = bounds;
-    mScreenBounds = mEffectiveTransform.transform(mBounds);
-
-    // Use the layer's own shadow radius if set. Otherwise get the radius from
-    // parent.
-    if (s.shadowRadius > 0.f) {
-        mEffectiveShadowRadius = s.shadowRadius;
-    } else {
-        mEffectiveShadowRadius = parentShadowRadius;
-    }
-
-    // Shadow radius is passed down to only one layer so if the layer can draw shadows,
-    // don't pass it to its children.
-    const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius;
-
-    for (const sp<Layer>& child : mDrawingChildren) {
-        child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
-    }
-
-    if (mPotentialCursor) {
-        prepareCursorCompositionState();
-    }
-}
-
 Rect Layer::getCroppedBufferSize(const State& s) const {
     Rect size = getBufferSize(s);
     Rect crop = getCrop(s);
@@ -500,180 +325,6 @@
     return size;
 }
 
-void Layer::setupRoundedCornersCropCoordinates(Rect win,
-                                               const FloatRect& roundedCornersCrop) const {
-    // Translate win by the rounded corners rect coordinates, to have all values in
-    // layer coordinate space.
-    win.left -= roundedCornersCrop.left;
-    win.right -= roundedCornersCrop.left;
-    win.top -= roundedCornersCrop.top;
-    win.bottom -= roundedCornersCrop.top;
-}
-
-void Layer::prepareBasicGeometryCompositionState() {
-    const auto& drawingState{getDrawingState()};
-    const auto alpha = static_cast<float>(getAlpha());
-    const bool opaque = isOpaque(drawingState);
-    const bool usesRoundedCorners = hasRoundedCorners();
-
-    auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
-    if (!opaque || alpha != 1.0f) {
-        blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
-                                        : Hwc2::IComposerClient::BlendMode::COVERAGE;
-    }
-
-    // Please keep in sync with LayerSnapshotBuilder
-    auto* snapshot = editLayerSnapshot();
-    snapshot->outputFilter = getOutputFilter();
-    snapshot->isVisible = isVisible();
-    snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
-    snapshot->shadowSettings.length = mEffectiveShadowRadius;
-
-    snapshot->contentDirty = contentDirty;
-    contentDirty = false;
-
-    snapshot->geomLayerBounds = mBounds;
-    snapshot->geomLayerTransform = getTransform();
-    snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse();
-    snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState);
-    snapshot->localTransform = getActiveTransform(drawingState);
-    snapshot->localTransformInverse = snapshot->localTransform.inverse();
-    snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
-    snapshot->alpha = alpha;
-    snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
-    snapshot->blurRegions = getBlurRegions();
-}
-
-void Layer::prepareGeometryCompositionState() {
-    const auto& drawingState{getDrawingState()};
-    auto* snapshot = editLayerSnapshot();
-
-    // Please keep in sync with LayerSnapshotBuilder
-    snapshot->geomBufferSize = getBufferSize(drawingState);
-    snapshot->geomContentCrop = getBufferCrop();
-    snapshot->geomCrop = getCrop(drawingState);
-    snapshot->geomBufferTransform = getBufferTransform();
-    snapshot->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
-    snapshot->geomUsesSourceCrop = usesSourceCrop();
-    snapshot->isSecure = isSecure();
-
-    snapshot->metadata.clear();
-    const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
-    for (const auto& [key, mandatory] : supportedMetadata) {
-        const auto& genericLayerMetadataCompatibilityMap =
-                mFlinger->getGenericLayerMetadataKeyMap();
-        auto compatIter = genericLayerMetadataCompatibilityMap.find(key);
-        if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) {
-            continue;
-        }
-        const uint32_t id = compatIter->second;
-
-        auto it = drawingState.metadata.mMap.find(id);
-        if (it == std::end(drawingState.metadata.mMap)) {
-            continue;
-        }
-
-        snapshot->metadata.emplace(key,
-                                   compositionengine::GenericLayerMetadataEntry{mandatory,
-                                                                                it->second});
-    }
-}
-
-void Layer::preparePerFrameCompositionState() {
-    const auto& drawingState{getDrawingState()};
-    // Please keep in sync with LayerSnapshotBuilder
-    auto* snapshot = editLayerSnapshot();
-
-    snapshot->forceClientComposition = false;
-
-    snapshot->isColorspaceAgnostic = isColorSpaceAgnostic();
-    snapshot->dataspace = getDataSpace();
-    snapshot->colorTransform = getColorTransform();
-    snapshot->colorTransformIsIdentity = !hasColorTransform();
-    snapshot->surfaceDamage = surfaceDamageRegion;
-    snapshot->hasProtectedContent = isProtected();
-    snapshot->dimmingEnabled = isDimmingEnabled();
-    snapshot->currentHdrSdrRatio = getCurrentHdrSdrRatio();
-    snapshot->desiredHdrSdrRatio = getDesiredHdrSdrRatio();
-    snapshot->cachingHint = getCachingHint();
-
-    const bool usesRoundedCorners = hasRoundedCorners();
-
-    snapshot->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
-
-    // Force client composition for special cases known only to the front-end.
-    // Rounded corners no longer force client composition, since we may use a
-    // hole punch so that the layer will appear to have rounded corners.
-    if (drawShadows() || snapshot->stretchEffect.hasEffect()) {
-        snapshot->forceClientComposition = true;
-    }
-    // If there are no visible region changes, we still need to update blur parameters.
-    snapshot->blurRegions = getBlurRegions();
-    snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
-
-    // Layer framerate is used in caching decisions.
-    // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
-    // LayerFECompositionState where it would be visible to Flattener.
-    snapshot->fps = mFlinger->getLayerFramerate(systemTime(), getSequence());
-
-    if (hasBufferOrSidebandStream()) {
-        preparePerFrameBufferCompositionState();
-    } else {
-        preparePerFrameEffectsCompositionState();
-    }
-}
-
-void Layer::preparePerFrameBufferCompositionState() {
-    // Please keep in sync with LayerSnapshotBuilder
-    auto* snapshot = editLayerSnapshot();
-    // Sideband layers
-    if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) {
-        snapshot->compositionType =
-                aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
-        return;
-    } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
-        snapshot->compositionType =
-                aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
-    } else if ((mDrawingState.flags & layer_state_t::eLayerIsRefreshRateIndicator) != 0) {
-        snapshot->compositionType =
-                aidl::android::hardware::graphics::composer3::Composition::REFRESH_RATE_INDICATOR;
-    } else {
-        // Normal buffer layers
-        snapshot->hdrMetadata = mBufferInfo.mHdrMetadata;
-        snapshot->compositionType = mPotentialCursor
-                ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
-                : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
-    }
-
-    snapshot->buffer = getBuffer();
-    snapshot->acquireFence = mBufferInfo.mFence;
-    snapshot->frameNumber = mBufferInfo.mFrameNumber;
-    snapshot->sidebandStreamHasFrame = false;
-}
-
-void Layer::preparePerFrameEffectsCompositionState() {
-    // Please keep in sync with LayerSnapshotBuilder
-    auto* snapshot = editLayerSnapshot();
-    snapshot->color = getColor();
-    snapshot->compositionType =
-            aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
-}
-
-void Layer::prepareCursorCompositionState() {
-    const State& drawingState{getDrawingState()};
-    // Please keep in sync with LayerSnapshotBuilder
-    auto* snapshot = editLayerSnapshot();
-
-    // Apply the layer's transform, followed by the display's global transform
-    // Here we're guaranteed that the layer's transform preserves rects
-    Rect win = getCroppedBufferSize(drawingState);
-    // Subtract the transparent region and snap to the bounds
-    Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
-    Rect frame(getTransform().transform(bounds));
-
-    snapshot->cursorFrame = frame;
-}
-
 const char* Layer::getDebugName() const {
     return mName.c_str();
 }
@@ -701,45 +352,18 @@
 }
 
 // ----------------------------------------------------------------------------
-// local state
-// ----------------------------------------------------------------------------
-
-bool Layer::isSecure() const {
-    const State& s(mDrawingState);
-    if (s.flags & layer_state_t::eLayerSecure) {
-        return true;
-    }
-
-    const auto p = mDrawingParent.promote();
-    return (p != nullptr) ? p->isSecure() : false;
-}
-
-// ----------------------------------------------------------------------------
 // transaction
 // ----------------------------------------------------------------------------
 
 uint32_t Layer::doTransaction(uint32_t flags) {
     SFTRACE_CALL();
 
-    // TODO: This is unfortunate.
-    mDrawingStateModified = mDrawingState.modified;
-    mDrawingState.modified = false;
-
     const State& s(getDrawingState());
 
-    if (updateGeometry()) {
-        // invalidate and recompute the visible regions if needed
-        flags |= Layer::eVisibleRegion;
-    }
-
     if (s.sequence != mLastCommittedTxSequence) {
         // invalidate and recompute the visible regions if needed
         mLastCommittedTxSequence = s.sequence;
         flags |= eVisibleRegion;
-        this->contentDirty = true;
-
-        // we may use linear filtering, if the matrix scales us
-        mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering();
     }
 
     if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) {
@@ -775,208 +399,11 @@
     mTransactionFlags |= mask;
 }
 
-bool Layer::setLayer(int32_t z) {
-    if (mDrawingState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false;
-    mDrawingState.sequence++;
-    mDrawingState.z = z;
-    mDrawingState.modified = true;
-
-    mFlinger->mSomeChildrenChanged = true;
-
-    // Discard all relative layering.
-    if (mDrawingState.zOrderRelativeOf != nullptr) {
-        sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
-        if (strongRelative != nullptr) {
-            strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
-        }
-        setZOrderRelativeOf(nullptr);
-    }
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-void Layer::removeZOrderRelative(const wp<Layer>& relative) {
-    mDrawingState.zOrderRelatives.remove(relative);
-    mDrawingState.sequence++;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-}
-
-void Layer::addZOrderRelative(const wp<Layer>& relative) {
-    mDrawingState.zOrderRelatives.add(relative);
-    mDrawingState.modified = true;
-    mDrawingState.sequence++;
-    setTransactionFlags(eTransactionNeeded);
-}
-
-void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) {
-    mDrawingState.zOrderRelativeOf = relativeOf;
-    mDrawingState.sequence++;
-    mDrawingState.modified = true;
-    mDrawingState.isRelativeOf = relativeOf != nullptr;
-
-    setTransactionFlags(eTransactionNeeded);
-}
-
-bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
-    sp<Layer> relative = LayerHandle::getLayer(relativeToHandle);
-    if (relative == nullptr) {
-        return false;
-    }
-
-    if (mDrawingState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) &&
-        mDrawingState.zOrderRelativeOf == relative) {
-        return false;
-    }
-
-    if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) &&
-        (relative->mDrawingState.zOrderRelativeOf == this)) {
-        ALOGE("Detected relative layer loop between %s and %s",
-              mName.c_str(), relative->mName.c_str());
-        ALOGE("Ignoring new call to set relative layer");
-        return false;
-    }
-
-    mFlinger->mSomeChildrenChanged = true;
-
-    mDrawingState.sequence++;
-    mDrawingState.modified = true;
-    mDrawingState.z = relativeZ;
-
-    auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
-    if (oldZOrderRelativeOf != nullptr) {
-        oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
-    }
-    setZOrderRelativeOf(relative);
-    relative->addZOrderRelative(wp<Layer>::fromExisting(this));
-
-    setTransactionFlags(eTransactionNeeded);
-
-    return true;
-}
-
-bool Layer::setTrustedOverlay(bool isTrustedOverlay) {
-    if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false;
-    mDrawingState.isTrustedOverlay = isTrustedOverlay;
-    mDrawingState.modified = true;
-    mFlinger->mUpdateInputInfo = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::isTrustedOverlay() const {
-    if (getDrawingState().isTrustedOverlay) {
-        return true;
-    }
-    const auto& p = mDrawingParent.promote();
-    return (p != nullptr) && p->isTrustedOverlay();
-}
-
-bool Layer::setAlpha(float alpha) {
-    if (mDrawingState.color.a == alpha) return false;
-    mDrawingState.sequence++;
-    mDrawingState.color.a = alpha;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setCornerRadius(float cornerRadius) {
-    if (mDrawingState.cornerRadius == cornerRadius) return false;
-
-    mDrawingState.sequence++;
-    mDrawingState.cornerRadius = cornerRadius;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
-    if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false;
-    // If we start or stop drawing blur then the layer's visibility state may change so increment
-    // the magic sequence number.
-    if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) {
-        mDrawingState.sequence++;
-    }
-    mDrawingState.backgroundBlurRadius = backgroundBlurRadius;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setTransparentRegionHint(const Region& transparent) {
-    mDrawingState.sequence++;
-    mDrawingState.transparentRegionHint = transparent;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
-    // If we start or stop drawing blur then the layer's visibility state may change so increment
-    // the magic sequence number.
-    if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) {
-        mDrawingState.sequence++;
-    }
-    mDrawingState.blurRegions = blurRegions;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setFlags(uint32_t flags, uint32_t mask) {
-    const uint32_t newFlags = (mDrawingState.flags & ~mask) | (flags & mask);
-    if (mDrawingState.flags == newFlags) return false;
-    mDrawingState.sequence++;
-    mDrawingState.flags = newFlags;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
 bool Layer::setCrop(const Rect& crop) {
     if (mDrawingState.crop == crop) return false;
     mDrawingState.sequence++;
     mDrawingState.crop = crop;
 
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setMetadata(const LayerMetadata& data) {
-    if (!mDrawingState.metadata.merge(data, true /* eraseEmpty */)) return false;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setLayerStack(ui::LayerStack layerStack) {
-    if (mDrawingState.layerStack == layerStack) return false;
-    mDrawingState.sequence++;
-    mDrawingState.layerStack = layerStack;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setColorSpaceAgnostic(const bool agnostic) {
-    if (mDrawingState.colorSpaceAgnostic == agnostic) {
-        return false;
-    }
-    mDrawingState.sequence++;
-    mDrawingState.colorSpaceAgnostic = agnostic;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setDimmingEnabled(const bool dimmingEnabled) {
-    if (mDrawingState.dimmingEnabled == dimmingEnabled) return false;
-
-    mDrawingState.sequence++;
-    mDrawingState.dimmingEnabled = dimmingEnabled;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -985,52 +412,6 @@
     return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
 };
 
-ui::LayerStack Layer::getLayerStack(LayerVector::StateSet state) const {
-    bool useDrawing = state == LayerVector::StateSet::Drawing;
-    const auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
-    if (parent) {
-        return parent->getLayerStack();
-    }
-    return getDrawingState().layerStack;
-}
-
-bool Layer::setShadowRadius(float shadowRadius) {
-    if (mDrawingState.shadowRadius == shadowRadius) {
-        return false;
-    }
-
-    mDrawingState.sequence++;
-    mDrawingState.shadowRadius = shadowRadius;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) {
-    if (mDrawingState.fixedTransformHint == fixedTransformHint) {
-        return false;
-    }
-
-    mDrawingState.sequence++;
-    mDrawingState.fixedTransformHint = fixedTransformHint;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setStretchEffect(const StretchEffect& effect) {
-    StretchEffect temp = effect;
-    temp.sanitize();
-    if (mDrawingState.stretchEffect == temp) {
-        return false;
-    }
-    mDrawingState.sequence++;
-    mDrawingState.stretchEffect = temp;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
 void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
                                                       nsecs_t postTime, gui::GameMode gameMode) {
     mDrawingState.postTime = postTime;
@@ -1059,7 +440,6 @@
                                                           gui::GameMode gameMode) {
     mDrawingState.frameTimelineInfo = info;
     mDrawingState.postTime = postTime;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
 
     if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX;
@@ -1181,40 +561,6 @@
     return getDrawingState().frameRateForLayerTree;
 }
 
-bool Layer::isHiddenByPolicy() const {
-    const State& s(mDrawingState);
-    const auto& parent = mDrawingParent.promote();
-    if (parent != nullptr && parent->isHiddenByPolicy()) {
-        return true;
-    }
-    if (usingRelativeZ(LayerVector::StateSet::Drawing)) {
-        auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
-        if (zOrderRelativeOf != nullptr) {
-            if (zOrderRelativeOf->isHiddenByPolicy()) {
-                return true;
-            }
-        }
-    }
-    if (CC_UNLIKELY(!isTransformValid())) {
-        ALOGW("Hide layer %s because it has invalid transformation.", getDebugName());
-        return true;
-    }
-    return s.flags & layer_state_t::eLayerHidden;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const {
-    // TODO: should we do something special if mSecure is set?
-    if (mProtectedByApp) {
-        // need a hardware-protected path to external video sink
-        usage |= GraphicBuffer::USAGE_PROTECTED;
-    }
-    if (mPotentialCursor) {
-        usage |= GraphicBuffer::USAGE_CURSOR;
-    }
-    usage |= GraphicBuffer::USAGE_HW_COMPOSER;
-    return usage;
-}
-
 // ----------------------------------------------------------------------------
 // debugging
 // ----------------------------------------------------------------------------
@@ -1293,248 +639,12 @@
     mFrameTracker.getStats(outStats);
 }
 
-void Layer::dumpOffscreenDebugInfo(std::string& result) const {
-    std::string hasBuffer = hasBufferOrSidebandStream() ? " (contains buffer)" : "";
-    StringAppendF(&result, "Layer %s%s pid:%d uid:%d%s\n", getName().c_str(), hasBuffer.c_str(),
-                  mOwnerPid, mOwnerUid, isHandleAlive() ? " handleAlive" : "");
-}
-
 void Layer::onDisconnect() {
     const int32_t layerId = getSequence();
     mFlinger->mTimeStats->onDestroy(layerId);
     mFlinger->mFrameTracer->onDestroy(layerId);
 }
 
-void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
-    for (const sp<Layer>& child : mDrawingChildren) {
-        child->mDrawingParent = newParent;
-        const float parentShadowRadius =
-                newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
-        child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
-                             parentShadowRadius);
-    }
-}
-
-bool Layer::setColorTransform(const mat4& matrix) {
-    static const mat4 identityMatrix = mat4();
-
-    if (mDrawingState.colorTransform == matrix) {
-        return false;
-    }
-    ++mDrawingState.sequence;
-    mDrawingState.colorTransform = matrix;
-    mDrawingState.hasColorTransform = matrix != identityMatrix;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-mat4 Layer::getColorTransform() const {
-    mat4 colorTransform = mat4(getDrawingState().colorTransform);
-    if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
-        colorTransform = parent->getColorTransform() * colorTransform;
-    }
-    return colorTransform;
-}
-
-bool Layer::hasColorTransform() const {
-    bool hasColorTransform = getDrawingState().hasColorTransform;
-    if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
-        hasColorTransform = hasColorTransform || parent->hasColorTransform();
-    }
-    return hasColorTransform;
-}
-
-bool Layer::isLegacyDataSpace() const {
-    // return true when no higher bits are set
-    return !(getDataSpace() &
-             (ui::Dataspace::STANDARD_MASK | ui::Dataspace::TRANSFER_MASK |
-              ui::Dataspace::RANGE_MASK));
-}
-
-void Layer::setParent(const sp<Layer>& layer) {
-    mCurrentParent = layer;
-}
-
-int32_t Layer::getZ(LayerVector::StateSet) const {
-    return mDrawingState.z;
-}
-
-bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) const {
-    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
-    const State& state = useDrawing ? mDrawingState : mDrawingState;
-    return state.isRelativeOf;
-}
-
-__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList(
-        LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers) {
-    LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
-                        "makeTraversalList received invalid stateSet");
-    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
-    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
-    const State& state = useDrawing ? mDrawingState : mDrawingState;
-
-    if (state.zOrderRelatives.size() == 0) {
-        *outSkipRelativeZUsers = true;
-        return children;
-    }
-
-    LayerVector traverse(stateSet);
-    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
-        sp<Layer> strongRelative = weakRelative.promote();
-        if (strongRelative != nullptr) {
-            traverse.add(strongRelative);
-        }
-    }
-
-    for (const sp<Layer>& child : children) {
-        if (child->usingRelativeZ(stateSet)) {
-            continue;
-        }
-        traverse.add(child);
-    }
-
-    return traverse;
-}
-
-ui::Transform Layer::getTransform() const {
-    return mEffectiveTransform;
-}
-
-bool Layer::isTransformValid() const {
-    float transformDet = getTransform().det();
-    return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet);
-}
-
-half Layer::getAlpha() const {
-    const auto& p = mDrawingParent.promote();
-
-    half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
-    return parentAlpha * getDrawingState().color.a;
-}
-
-ui::Transform::RotationFlags Layer::getFixedTransformHint() const {
-    ui::Transform::RotationFlags fixedTransformHint = mDrawingState.fixedTransformHint;
-    if (fixedTransformHint != ui::Transform::ROT_INVALID) {
-        return fixedTransformHint;
-    }
-    const auto& p = mCurrentParent.promote();
-    if (!p) return fixedTransformHint;
-    return p->getFixedTransformHint();
-}
-
-half4 Layer::getColor() const {
-    const half4 color(getDrawingState().color);
-    return half4(color.r, color.g, color.b, getAlpha());
-}
-
-int32_t Layer::getBackgroundBlurRadius() const {
-    if (getDrawingState().backgroundBlurRadius == 0) {
-        return 0;
-    }
-
-    const auto& p = mDrawingParent.promote();
-    half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
-    return parentAlpha * getDrawingState().backgroundBlurRadius;
-}
-
-const std::vector<BlurRegion> Layer::getBlurRegions() const {
-    auto regionsCopy(getDrawingState().blurRegions);
-    float layerAlpha = getAlpha();
-    for (auto& region : regionsCopy) {
-        region.alpha = region.alpha * layerAlpha;
-    }
-    return regionsCopy;
-}
-
-RoundedCornerState Layer::getRoundedCornerState() const {
-    // Today's DPUs cannot do rounded corners. If RenderEngine cannot render
-    // protected content, remove rounded corners from protected content so it
-    // can be rendered by the DPU.
-    if (isProtected() && !mFlinger->getRenderEngine().supportsProtectedContent()) {
-        return {};
-    }
-
-    // Get parent settings
-    RoundedCornerState parentSettings;
-    const auto& parent = mDrawingParent.promote();
-    if (parent != nullptr) {
-        parentSettings = parent->getRoundedCornerState();
-        if (parentSettings.hasRoundedCorners()) {
-            ui::Transform t = getActiveTransform(getDrawingState());
-            t = t.inverse();
-            parentSettings.cropRect = t.transform(parentSettings.cropRect);
-            parentSettings.radius.x *= t.getScaleX();
-            parentSettings.radius.y *= t.getScaleY();
-        }
-    }
-
-    // Get layer settings
-    Rect layerCropRect = getCroppedBufferSize(getDrawingState());
-    const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius);
-    RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
-    const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid();
-
-    if (layerSettingsValid && parentSettings.hasRoundedCorners()) {
-        // If the parent and the layer have rounded corner settings, use the parent settings if the
-        // parent crop is entirely inside the layer crop.
-        // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
-        if (parentSettings.cropRect.left > layerCropRect.left &&
-            parentSettings.cropRect.top > layerCropRect.top &&
-            parentSettings.cropRect.right < layerCropRect.right &&
-            parentSettings.cropRect.bottom < layerCropRect.bottom) {
-            return parentSettings;
-        } else {
-            return layerSettings;
-        }
-    } else if (layerSettingsValid) {
-        return layerSettings;
-    } else if (parentSettings.hasRoundedCorners()) {
-        return parentSettings;
-    }
-    return {};
-}
-
-bool Layer::findInHierarchy(const sp<Layer>& l) {
-    if (l == this) {
-        return true;
-    }
-    for (auto& child : mDrawingChildren) {
-      if (child->findInHierarchy(l)) {
-          return true;
-      }
-    }
-    return false;
-}
-
-void Layer::setInputInfo(const WindowInfo& info) {
-    mDrawingState.inputInfo = info;
-    mDrawingState.touchableRegionCrop =
-            LayerHandle::getLayer(info.touchableRegionCropHandle.promote());
-    mDrawingState.modified = true;
-    mFlinger->mUpdateInputInfo = true;
-    setTransactionFlags(eTransactionNeeded);
-}
-
-perfetto::protos::LayerProto* Layer::writeToProto(perfetto::protos::LayersProto& layersProto,
-                                                  uint32_t traceFlags) {
-    perfetto::protos::LayerProto* layerProto = layersProto.add_layers();
-    writeToProtoDrawingState(layerProto);
-    writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
-
-    if (traceFlags & LayerTracing::TRACE_COMPOSITION) {
-        ui::LayerStack layerStack =
-                (mSnapshot) ? mSnapshot->outputFilter.layerStack : ui::INVALID_LAYER_STACK;
-        writeCompositionStateToProto(layerProto, layerStack);
-    }
-
-    for (const sp<Layer>& layer : mDrawingChildren) {
-        layer->writeToProto(layersProto, traceFlags);
-    }
-
-    return layerProto;
-}
-
 void Layer::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
                                          ui::LayerStack layerStack) {
     ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread.
@@ -1550,352 +660,6 @@
     }
 }
 
-void Layer::writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo) {
-    const ui::Transform transform = getTransform();
-    auto buffer = getExternalTexture();
-    if (buffer != nullptr) {
-        LayerProtoHelper::writeToProto(*buffer,
-                                       [&]() { return layerInfo->mutable_active_buffer(); });
-        LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
-                                                 layerInfo->mutable_buffer_transform());
-    }
-    layerInfo->set_invalidate(contentDirty);
-    layerInfo->set_is_protected(isProtected());
-    layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
-    layerInfo->set_queued_frames(getQueuedFrameCount());
-    layerInfo->set_curr_frame(mCurrentFrameNumber);
-    layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
-    layerInfo->set_corner_radius(
-            (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0);
-    layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
-    layerInfo->set_is_trusted_overlay(isTrustedOverlay());
-    LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform());
-    LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
-                                           [&]() { return layerInfo->mutable_position(); });
-    LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
-    LayerProtoHelper::writeToProto(surfaceDamageRegion,
-                                   [&]() { return layerInfo->mutable_damage_region(); });
-
-    if (hasColorTransform()) {
-        LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform());
-    }
-
-    LayerProtoHelper::writeToProto(mSourceBounds,
-                                   [&]() { return layerInfo->mutable_source_bounds(); });
-    LayerProtoHelper::writeToProto(mScreenBounds,
-                                   [&]() { return layerInfo->mutable_screen_bounds(); });
-    LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
-                                   [&]() { return layerInfo->mutable_corner_radius_crop(); });
-    layerInfo->set_shadow_radius(mEffectiveShadowRadius);
-}
-
-void Layer::writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo,
-                                    LayerVector::StateSet stateSet, uint32_t traceFlags) {
-    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
-    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
-    const State& state = useDrawing ? mDrawingState : mDrawingState;
-
-    ui::Transform requestedTransform = state.transform;
-
-    layerInfo->set_id(sequence);
-    layerInfo->set_name(getName().c_str());
-    layerInfo->set_type(getType());
-
-    for (const auto& child : children) {
-        layerInfo->add_children(child->sequence);
-    }
-
-    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
-        sp<Layer> strongRelative = weakRelative.promote();
-        if (strongRelative != nullptr) {
-            layerInfo->add_relatives(strongRelative->sequence);
-        }
-    }
-
-    LayerProtoHelper::writeToProto(state.transparentRegionHint,
-                                   [&]() { return layerInfo->mutable_transparent_region(); });
-
-    layerInfo->set_layer_stack(getLayerStack().id);
-    layerInfo->set_z(state.z);
-
-    LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
-        return layerInfo->mutable_requested_position();
-    });
-
-    LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); });
-
-    layerInfo->set_is_opaque(isOpaque(state));
-
-    layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
-    LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
-    LayerProtoHelper::writeToProto(state.color,
-                                   [&]() { return layerInfo->mutable_requested_color(); });
-    layerInfo->set_flags(state.flags);
-
-    LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
-                                             layerInfo->mutable_requested_transform());
-
-    auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
-    if (parent != nullptr) {
-        layerInfo->set_parent(parent->sequence);
-    }
-
-    auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
-    if (zOrderRelativeOf != nullptr) {
-        layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
-    }
-
-    layerInfo->set_is_relative_of(state.isRelativeOf);
-
-    layerInfo->set_owner_uid(mOwnerUid);
-
-    if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
-        WindowInfo info;
-        if (useDrawing) {
-            info = fillInputInfo(
-                    InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true});
-        } else {
-            info = state.inputInfo;
-        }
-
-        LayerProtoHelper::writeToProto(info, state.touchableRegionCrop,
-                                       [&]() { return layerInfo->mutable_input_window_info(); });
-    }
-
-    if (traceFlags & LayerTracing::TRACE_EXTRA) {
-        auto protoMap = layerInfo->mutable_metadata();
-        for (const auto& entry : state.metadata.mMap) {
-            (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
-        }
-    }
-
-    LayerProtoHelper::writeToProto(state.destinationFrame,
-                                   [&]() { return layerInfo->mutable_destination_frame(); });
-}
-
-// Applies the given transform to the region, while protecting against overflows caused by any
-// offsets. If applying the offset in the transform to any of the Rects in the region would result
-// in an overflow, they are not added to the output Region.
-static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
-                                             const std::string& debugWindowName) {
-    // Round the translation using the same rounding strategy used by ui::Transform.
-    const auto tx = static_cast<int32_t>(t.tx() + 0.5);
-    const auto ty = static_cast<int32_t>(t.ty() + 0.5);
-
-    ui::Transform transformWithoutOffset = t;
-    transformWithoutOffset.set(0.f, 0.f);
-
-    const Region transformed = transformWithoutOffset.transform(r);
-
-    // Apply the translation to each of the Rects in the region while discarding any that overflow.
-    Region ret;
-    for (const auto& rect : transformed) {
-        Rect newRect;
-        if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
-            __builtin_add_overflow(rect.top, ty, &newRect.top) ||
-            __builtin_add_overflow(rect.right, tx, &newRect.right) ||
-            __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
-            ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
-                  debugWindowName.c_str());
-            continue;
-        }
-        ret.orSelf(newRect);
-    }
-    return ret;
-}
-
-void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) {
-    auto [inputBounds, inputBoundsValid] = getInputBounds(/*fillParentBounds=*/false);
-    if (!inputBoundsValid) {
-        info.touchableRegion.clear();
-    }
-
-    info.frame = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay);
-
-    ui::Transform inputToLayer;
-    inputToLayer.set(inputBounds.left, inputBounds.top);
-    const ui::Transform layerToScreen = getInputTransform();
-    const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
-
-    // InputDispatcher expects a display-to-input transform.
-    info.transform = inputToDisplay.inverse();
-
-    // The touchable region is specified in the input coordinate space. Change it to display space.
-    info.touchableRegion =
-            transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName);
-}
-
-void Layer::fillTouchOcclusionMode(WindowInfo& info) {
-    sp<Layer> p = sp<Layer>::fromExisting(this);
-    while (p != nullptr && !p->hasInputInfo()) {
-        p = p->mDrawingParent.promote();
-    }
-    if (p != nullptr) {
-        info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode;
-    }
-}
-
-gui::DropInputMode Layer::getDropInputMode() const {
-    gui::DropInputMode mode = mDrawingState.dropInputMode;
-    if (mode == gui::DropInputMode::ALL) {
-        return mode;
-    }
-    sp<Layer> parent = mDrawingParent.promote();
-    if (parent) {
-        gui::DropInputMode parentMode = parent->getDropInputMode();
-        if (parentMode != gui::DropInputMode::NONE) {
-            return parentMode;
-        }
-    }
-    return mode;
-}
-
-void Layer::handleDropInputMode(gui::WindowInfo& info) const {
-    if (mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
-        return;
-    }
-
-    // Check if we need to drop input unconditionally
-    gui::DropInputMode dropInputMode = getDropInputMode();
-    if (dropInputMode == gui::DropInputMode::ALL) {
-        info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
-        ALOGV("Dropping input for %s as requested by policy.", getDebugName());
-        return;
-    }
-
-    // Check if we need to check if the window is obscured by parent
-    if (dropInputMode != gui::DropInputMode::OBSCURED) {
-        return;
-    }
-
-    // Check if the parent has set an alpha on the layer
-    sp<Layer> parent = mDrawingParent.promote();
-    if (parent && parent->getAlpha() != 1.0_hf) {
-        info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
-        ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
-              static_cast<float>(getAlpha()));
-    }
-
-    // Check if the parent has cropped the buffer
-    Rect bufferSize = getCroppedBufferSize(getDrawingState());
-    if (!bufferSize.isValid()) {
-        info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
-        return;
-    }
-
-    // Screenbounds are the layer bounds cropped by parents, transformed to screenspace.
-    // To check if the layer has been cropped, we take the buffer bounds, apply the local
-    // layer crop and apply the same set of transforms to move to screenspace. If the bounds
-    // match then the layer has not been cropped by its parents.
-    Rect bufferInScreenSpace(getTransform().transform(bufferSize));
-    bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds};
-
-    if (croppedByParent) {
-        info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
-        ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent",
-              getDebugName());
-    } else {
-        // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop
-        // input if the window is obscured. This check should be done in surfaceflinger but the
-        // logic currently resides in inputflinger. So pass the if_obscured check to input to only
-        // drop input events if the window is obscured.
-        info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
-    }
-}
-
-WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
-    if (!hasInputInfo()) {
-        mDrawingState.inputInfo.name = getName();
-        mDrawingState.inputInfo.ownerUid = gui::Uid{mOwnerUid};
-        mDrawingState.inputInfo.ownerPid = gui::Pid{mOwnerPid};
-        mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL;
-        mDrawingState.inputInfo.displayId = toLogicalDisplayId(getLayerStack());
-    }
-
-    const ui::Transform& displayTransform =
-            displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform;
-
-    WindowInfo info = mDrawingState.inputInfo;
-    info.id = sequence;
-    info.displayId = toLogicalDisplayId(getLayerStack());
-
-    fillInputFrameInfo(info, displayTransform);
-
-    if (displayArgs.transform == nullptr) {
-        // Do not let the window receive touches if it is not associated with a valid display
-        // transform. We still allow the window to receive keys and prevent ANRs.
-        info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
-    }
-
-    info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !isVisibleForInput());
-
-    info.alpha = getAlpha();
-    fillTouchOcclusionMode(info);
-    handleDropInputMode(info);
-
-    // If the window will be blacked out on a display because the display does not have the secure
-    // flag and the layer has the secure flag set, then drop input.
-    if (!displayArgs.isSecure && isSecure()) {
-        info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
-    }
-
-    sp<Layer> cropLayer = mDrawingState.touchableRegionCrop.promote();
-    if (info.replaceTouchableRegionWithCrop) {
-        Rect inputBoundsInDisplaySpace;
-        if (!cropLayer) {
-            FloatRect inputBounds = getInputBounds(/*fillParentBounds=*/true).first;
-            inputBoundsInDisplaySpace = getInputBoundsInDisplaySpace(inputBounds, displayTransform);
-        } else {
-            FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
-            inputBoundsInDisplaySpace =
-                    cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
-        }
-        info.touchableRegion = Region(inputBoundsInDisplaySpace);
-    } else if (cropLayer != nullptr) {
-        FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first;
-        Rect inputBoundsInDisplaySpace =
-                cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform);
-        info.touchableRegion = info.touchableRegion.intersect(inputBoundsInDisplaySpace);
-    }
-
-    // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
-    // if it was set by WM for a known system overlay
-    if (isTrustedOverlay()) {
-        info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY;
-    }
-
-    Rect bufferSize = getBufferSize(getDrawingState());
-    info.contentSize = Size(bufferSize.width(), bufferSize.height());
-
-    return info;
-}
-
-Rect Layer::getInputBoundsInDisplaySpace(const FloatRect& inputBounds,
-                                         const ui::Transform& screenToDisplay) {
-    // InputDispatcher works in the display device's coordinate space. Here, we calculate the
-    // frame and transform used for the layer, which determines the bounds and the coordinate space
-    // within which the layer will receive input.
-
-    // Coordinate space definitions:
-    //   - display: The display device's coordinate space. Correlates to pixels on the display.
-    //   - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
-    //   - layer: The coordinate space of this layer.
-    //   - input: The coordinate space in which this layer will receive input events. This could be
-    //            different than layer space if a surfaceInset is used, which changes the origin
-    //            of the input space.
-
-    // Crop the input bounds to ensure it is within the parent's bounds.
-    const FloatRect croppedInputBounds = mBounds.intersect(inputBounds);
-    const ui::Transform layerToScreen = getInputTransform();
-    const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
-    return Rect{layerToDisplay.transform(croppedInputBounds)};
-}
-
-bool Layer::hasInputInfo() const {
-    return mDrawingState.inputInfo.token != nullptr ||
-            mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
-}
-
 compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
         const DisplayDevice* display) const {
     if (!display) return nullptr;
@@ -1930,24 +694,6 @@
     return outputLayer ? outputLayer->getState().visibleRegion : Region();
 }
 
-bool Layer::isInternalDisplayOverlay() const {
-    const State& s(mDrawingState);
-    if (s.flags & layer_state_t::eLayerSkipScreenshot) {
-        return true;
-    }
-
-    sp<Layer> parent = mDrawingParent.promote();
-    return parent && parent->isInternalDisplayOverlay();
-}
-
-bool Layer::setDropInputMode(gui::DropInputMode mode) {
-    if (mDrawingState.dropInputMode == mode) {
-        return false;
-    }
-    mDrawingState.dropInputMode = mode;
-    return true;
-}
-
 void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
                                       const sp<GraphicBuffer>& buffer, uint64_t framenumber,
                                       const sp<Fence>& releaseFence) {
@@ -2106,17 +852,9 @@
     mDrawingState.callbackHandles = {};
 }
 
-bool Layer::willPresentCurrentTransaction() const {
-    // Returns true if the most recent Transaction applied to CurrentState will be presented.
-    return (getSidebandStreamChanged() || getAutoRefresh() ||
-            (mDrawingState.modified &&
-             (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr)));
-}
-
 bool Layer::setTransform(uint32_t transform) {
     if (mDrawingState.bufferTransform == transform) return false;
     mDrawingState.bufferTransform = transform;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -2125,7 +863,6 @@
     if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
     mDrawingState.sequence++;
     mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -2136,100 +873,10 @@
     mDrawingState.sequence++;
     mDrawingState.bufferCrop = bufferCrop;
 
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
 
-bool Layer::setDestinationFrame(const Rect& destinationFrame) {
-    if (mDrawingState.destinationFrame == destinationFrame) return false;
-
-    mDrawingState.sequence++;
-    mDrawingState.destinationFrame = destinationFrame;
-
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-// Translate destination frame into scale and position. If a destination frame is not set, use the
-// provided scale and position
-bool Layer::updateGeometry() {
-    if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
-        mDrawingState.destinationFrame.isEmpty()) {
-        // If destination frame is not set, use the requested transform set via
-        // Layer::setPosition and Layer::setMatrix.
-        return assignTransform(&mDrawingState.transform, mRequestedTransform);
-    }
-
-    Rect destRect = mDrawingState.destinationFrame;
-    int32_t destW = destRect.width();
-    int32_t destH = destRect.height();
-    if (destRect.left < 0) {
-        destRect.left = 0;
-        destRect.right = destW;
-    }
-    if (destRect.top < 0) {
-        destRect.top = 0;
-        destRect.bottom = destH;
-    }
-
-    if (!mDrawingState.buffer) {
-        ui::Transform t;
-        t.set(destRect.left, destRect.top);
-        return assignTransform(&mDrawingState.transform, t);
-    }
-
-    uint32_t bufferWidth = mDrawingState.buffer->getWidth();
-    uint32_t bufferHeight = mDrawingState.buffer->getHeight();
-    // Undo any transformations on the buffer.
-    if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
-        std::swap(bufferWidth, bufferHeight);
-    }
-    uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags();
-    if (mDrawingState.transformToDisplayInverse) {
-        if (invTransform & ui::Transform::ROT_90) {
-            std::swap(bufferWidth, bufferHeight);
-        }
-    }
-
-    float sx = destW / static_cast<float>(bufferWidth);
-    float sy = destH / static_cast<float>(bufferHeight);
-    ui::Transform t;
-    t.set(sx, 0, 0, sy);
-    t.set(destRect.left, destRect.top);
-    return assignTransform(&mDrawingState.transform, t);
-}
-
-bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
-    if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
-        mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
-        return false;
-    }
-
-    mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
-    mDrawingState.sequence++;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-
-    return true;
-}
-
-bool Layer::setPosition(float x, float y) {
-    if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
-        return false;
-    }
-
-    mRequestedTransform.set(x, y);
-
-    mDrawingState.sequence++;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-
-    return true;
-}
-
 void Layer::releasePreviousBuffer() {
     mReleasePreviousBuffer = true;
     if (!mBufferInfo.mBuffer ||
@@ -2293,7 +940,6 @@
     mDrawingState.isAutoTimestamp = isAutoTimestamp;
     mDrawingState.latchedVsyncId = info.vsyncId;
     mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection;
-    mDrawingState.modified = true;
     if (!buffer) {
         resetDrawingStateBufferInfo();
         setTransactionFlags(eTransactionNeeded);
@@ -2441,7 +1087,6 @@
 bool Layer::setDataspace(ui::Dataspace dataspace) {
     if (mDrawingState.dataspace == dataspace) return false;
     mDrawingState.dataspace = dataspace;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -2452,7 +1097,6 @@
         return false;
     mDrawingState.currentHdrSdrRatio = currentBufferRatio;
     mDrawingState.desiredHdrSdrRatio = desiredRatio;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -2460,40 +1104,6 @@
 bool Layer::setDesiredHdrHeadroom(float desiredRatio) {
     if (mDrawingState.desiredHdrSdrRatio == desiredRatio) return false;
     mDrawingState.desiredHdrSdrRatio = desiredRatio;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setCachingHint(gui::CachingHint cachingHint) {
-    if (mDrawingState.cachingHint == cachingHint) return false;
-    mDrawingState.cachingHint = cachingHint;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
-    if (mDrawingState.hdrMetadata == hdrMetadata) return false;
-    mDrawingState.hdrMetadata = hdrMetadata;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) {
-    if (mDrawingState.surfaceDamageRegion.hasSameRects(surfaceDamage)) return false;
-    mDrawingState.surfaceDamageRegion = surfaceDamage;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    setIsSmallDirty(surfaceDamage, getTransform());
-    return true;
-}
-
-bool Layer::setApi(int32_t api) {
-    if (mDrawingState.api == api) return false;
-    mDrawingState.api = api;
-    mDrawingState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -2509,7 +1119,6 @@
     }
 
     mDrawingState.sidebandStream = sidebandStream;
-    mDrawingState.modified = true;
     if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) {
         releasePreviousBuffer();
         resetDrawingStateBufferInfo();
@@ -2606,14 +1215,6 @@
     return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
 }
 
-FloatRect Layer::computeSourceBounds(const FloatRect& parentBounds) const {
-    if (mBufferInfo.mBuffer == nullptr) {
-        return parentBounds;
-    }
-
-    return getBufferSize(getDrawingState()).toFloatRect();
-}
-
 bool Layer::fenceHasSignaled() const {
     if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
         return true;
@@ -2635,37 +1236,21 @@
     }
 }
 
-void Layer::setAutoRefresh(bool autoRefresh) {
-    mDrawingState.autoRefresh = autoRefresh;
-}
-
 bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) {
-    // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
-    auto* snapshot = editLayerSnapshot();
-    snapshot->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
-
     if (mSidebandStreamChanged.exchange(false)) {
         const State& s(getDrawingState());
         // mSidebandStreamChanged was true
         mSidebandStream = s.sidebandStream;
-        snapshot->sidebandStream = mSidebandStream;
         if (mSidebandStream != nullptr) {
             setTransactionFlags(eTransactionNeeded);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
         recomputeVisibleRegions = true;
-
         return true;
     }
     return false;
 }
 
-bool Layer::hasFrameUpdate() const {
-    const State& c(getDrawingState());
-    return (mDrawingStateModified || mDrawingState.modified) &&
-            (c.buffer != nullptr || c.bgColorLayer != nullptr);
-}
-
 void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) {
     const State& s(getDrawingState());
 
@@ -2712,8 +1297,6 @@
     mFlinger->getTransactionCallbackInvoker()
             .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
     mDrawingState.callbackHandles = remainingHandles;
-
-    mDrawingStateModified = false;
 }
 
 void Layer::gatherBufferInfo() {
@@ -2737,7 +1320,6 @@
     mBufferInfo.mFrameLatencyNeeded = true;
     mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
     mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
-    mBufferInfo.mFence = mDrawingState.acquireFence;
     mBufferInfo.mTransform = mDrawingState.bufferTransform;
     auto lastDataspace = mBufferInfo.mDataspace;
     mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
@@ -2785,10 +1367,6 @@
         mFlinger->mHdrLayerInfoChanged = true;
     }
     mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
-    mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
-    mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
-    mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
-    mBufferInfo.mApi = mDrawingState.api;
     mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
 }
 
@@ -2813,294 +1391,6 @@
     SFTRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
 }
 
-/*
- * We don't want to send the layer's transform to input, but rather the
- * parent's transform. This is because Layer's transform is
- * information about how the buffer is placed on screen. The parent's
- * transform makes more sense to send since it's information about how the
- * layer is placed on screen. This transform is used by input to determine
- * how to go from screen space back to window space.
- */
-ui::Transform Layer::getInputTransform() const {
-    if (!hasBufferOrSidebandStream()) {
-        return getTransform();
-    }
-    sp<Layer> parent = mDrawingParent.promote();
-    if (parent == nullptr) {
-        return ui::Transform();
-    }
-
-    return parent->getTransform();
-}
-
-/**
- * Returns the bounds used to fill the input frame and the touchable region.
- *
- * Similar to getInputTransform, we need to update the bounds to include the transform.
- * This is because bounds don't include the buffer transform, where the input assumes
- * that's already included.
- */
-std::pair<FloatRect, bool> Layer::getInputBounds(bool fillParentBounds) const {
-    Rect croppedBufferSize = getCroppedBufferSize(getDrawingState());
-    FloatRect inputBounds = croppedBufferSize.toFloatRect();
-    if (hasBufferOrSidebandStream() && croppedBufferSize.isValid() &&
-        mDrawingState.transform.getType() != ui::Transform::IDENTITY) {
-        inputBounds = mDrawingState.transform.transform(inputBounds);
-    }
-
-    bool inputBoundsValid = croppedBufferSize.isValid();
-    if (!inputBoundsValid) {
-        /**
-         * Input bounds are based on the layer crop or buffer size. But if we are using
-         * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then
-         * we can use the parent bounds as the input bounds if the layer does not have buffer
-         * or a crop. We want to unify this logic but because of compat reasons we cannot always
-         * use the parent bounds. A layer without a buffer can get input. So when a window is
-         * initially added, its touchable region can fill its parent layer bounds and that can
-         * have negative consequences.
-         */
-        inputBounds = fillParentBounds ? mBounds : FloatRect{};
-    }
-
-    // Clamp surface inset to the input bounds.
-    const float inset = static_cast<float>(mDrawingState.inputInfo.surfaceInset);
-    const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f);
-    const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f);
-
-    // Apply the insets to the input bounds.
-    inputBounds.left += xSurfaceInset;
-    inputBounds.top += ySurfaceInset;
-    inputBounds.right -= xSurfaceInset;
-    inputBounds.bottom -= ySurfaceInset;
-
-    return {inputBounds, inputBoundsValid};
-}
-
-bool Layer::isSimpleBufferUpdate(const layer_state_t& s) const {
-    const uint64_t requiredFlags = layer_state_t::eBufferChanged;
-
-    const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
-            layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
-            layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
-            layer_state_t::eLayerStackChanged | layer_state_t::eReparent |
-            (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
-                     ? 0
-                     : layer_state_t::eAutoRefreshChanged);
-
-    if ((s.what & requiredFlags) != requiredFlags) {
-        SFTRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
-                               (s.what | requiredFlags) & ~s.what);
-        return false;
-    }
-
-    if (s.what & deniedFlags) {
-        SFTRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__,
-                               s.what & deniedFlags);
-        return false;
-    }
-
-    if (s.what & layer_state_t::ePositionChanged) {
-        if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
-            SFTRACE_FORMAT_INSTANT("%s: false [ePositionChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eAlphaChanged) {
-        if (mDrawingState.color.a != s.color.a) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eAlphaChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eColorTransformChanged) {
-        if (mDrawingState.colorTransform != s.colorTransform) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eColorTransformChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eBackgroundColorChanged) {
-        if (mDrawingState.bgColorLayer || s.bgColor.a != 0) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundColorChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eMatrixChanged) {
-        if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
-            mRequestedTransform.dtdy() != s.matrix.dtdy ||
-            mRequestedTransform.dtdx() != s.matrix.dtdx ||
-            mRequestedTransform.dsdy() != s.matrix.dsdy) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eMatrixChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eCornerRadiusChanged) {
-        if (mDrawingState.cornerRadius != s.cornerRadius) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eCornerRadiusChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
-        if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eBufferTransformChanged) {
-        if (mDrawingState.bufferTransform != s.bufferTransform) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eBufferTransformChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
-        if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eTransformToDisplayInverseChanged changed]",
-                                   __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eCropChanged) {
-        if (mDrawingState.crop != s.crop) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eCropChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eDataspaceChanged) {
-        if (mDrawingState.dataspace != s.dataspace) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eDataspaceChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eHdrMetadataChanged) {
-        if (mDrawingState.hdrMetadata != s.hdrMetadata) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eHdrMetadataChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eSidebandStreamChanged) {
-        if (mDrawingState.sidebandStream != s.sidebandStream) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eSidebandStreamChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
-        if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eShadowRadiusChanged) {
-        if (mDrawingState.shadowRadius != s.shadowRadius) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eShadowRadiusChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eFixedTransformHintChanged) {
-        if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eFixedTransformHintChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eTrustedOverlayChanged) {
-        if (mDrawingState.isTrustedOverlay != (s.trustedOverlay == gui::TrustedOverlay::ENABLED)) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eTrustedOverlayChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eStretchChanged) {
-        StretchEffect temp = s.stretchEffect;
-        temp.sanitize();
-        if (mDrawingState.stretchEffect != temp) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eStretchChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eBufferCropChanged) {
-        if (mDrawingState.bufferCrop != s.bufferCrop) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eBufferCropChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eDestinationFrameChanged) {
-        if (mDrawingState.destinationFrame != s.destinationFrame) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eDestinationFrameChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eDimmingEnabledChanged) {
-        if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eDimmingEnabledChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eExtendedRangeBrightnessChanged) {
-        if (mDrawingState.currentHdrSdrRatio != s.currentHdrSdrRatio ||
-            mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eExtendedRangeBrightnessChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    if (s.what & layer_state_t::eDesiredHdrHeadroomChanged) {
-        if (mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) {
-            SFTRACE_FORMAT_INSTANT("%s: false [eDesiredHdrHeadroomChanged changed]", __func__);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-sp<LayerFE> Layer::getCompositionEngineLayerFE() const {
-    // There's no need to get a CE Layer if the layer isn't going to draw anything.
-    return hasSomethingToDraw() ? mLegacyLayerFE : nullptr;
-}
-
-const LayerSnapshot* Layer::getLayerSnapshot() const {
-    return mSnapshot.get();
-}
-
-LayerSnapshot* Layer::editLayerSnapshot() {
-    return mSnapshot.get();
-}
-
-std::unique_ptr<frontend::LayerSnapshot> Layer::stealLayerSnapshot() {
-    return std::move(mSnapshot);
-}
-
-void Layer::updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot) {
-    mSnapshot = std::move(snapshot);
-}
-
-const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
-    return mSnapshot.get();
-}
-
-sp<LayerFE> Layer::copyCompositionEngineLayerFE() const {
-    auto result = mFlinger->getFactory().createLayerFE(mName, this);
-    result->mSnapshot = std::make_unique<LayerSnapshot>(*mSnapshot);
-    return result;
-}
-
 sp<LayerFE> Layer::getCompositionEngineLayerFE(
         const frontend::LayerHierarchy::TraversalPath& path) {
     for (auto& [p, layerFE] : mLayerFEs) {
@@ -3113,55 +1403,6 @@
     return layerFE;
 }
 
-void Layer::useSurfaceDamage() {
-    if (mFlinger->mForceFullDamage) {
-        surfaceDamageRegion = Region::INVALID_REGION;
-    } else {
-        surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
-    }
-}
-
-void Layer::useEmptyDamage() {
-    surfaceDamageRegion.clear();
-}
-
-bool Layer::isOpaque(const Layer::State& s) const {
-    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
-    // layer's opaque flag.
-    if (!hasSomethingToDraw()) {
-        return false;
-    }
-
-    // if the layer has the opaque flag, then we're always opaque
-    if ((s.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque) {
-        return true;
-    }
-
-    // If the buffer has no alpha channel, then we are opaque
-    if (hasBufferOrSidebandStream() && LayerSnapshot::isOpaqueFormat(getPixelFormat())) {
-        return true;
-    }
-
-    // Lastly consider the layer opaque if drawing a color with alpha == 1.0
-    return fillsColor() && getAlpha() == 1.0_hf;
-}
-
-bool Layer::canReceiveInput() const {
-    return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
-}
-
-bool Layer::isVisible() const {
-    if (!hasSomethingToDraw()) {
-        return false;
-    }
-
-    if (isHiddenByPolicy()) {
-        return false;
-    }
-
-    return getAlpha() > 0.0f || hasBlur();
-}
-
 void Layer::onCompositionPresented(const DisplayDevice* display,
                                    const std::shared_ptr<FenceTime>& glDoneFence,
                                    const std::shared_ptr<FenceTime>& presentFence,
@@ -3254,11 +1495,6 @@
     return !mDrawingState.buffer && mBufferInfo.mBuffer;
 }
 
-bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
-    const bool bgColorOnly = mDrawingState.bgColorLayer != nullptr;
-    return latchBufferImpl(recomputeVisibleRegions, latchTime, bgColorOnly);
-}
-
 bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) {
     SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
                            getDrawingState().frameNumber);
@@ -3280,7 +1516,6 @@
 
     // Capture the old state of the layer for comparisons later
     BufferInfo oldBufferInfo = mBufferInfo;
-    const bool oldOpacity = isOpaque(mDrawingState);
     mPreviousFrameNumber = mCurrentFrameNumber;
     mCurrentFrameNumber = mDrawingState.frameNumber;
     gatherBufferInfo();
@@ -3305,7 +1540,6 @@
 
     if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
         (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
-        (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
         (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
         recomputeVisibleRegions = true;
     }
@@ -3318,35 +1552,14 @@
             recomputeVisibleRegions = true;
         }
     }
-
-    if (oldOpacity != isOpaque(mDrawingState)) {
-        recomputeVisibleRegions = true;
-    }
-
     return true;
 }
 
-bool Layer::hasReadyFrame() const {
-    return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
-}
-
 bool Layer::isProtected() const {
     return (mBufferInfo.mBuffer != nullptr) &&
             (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
-void Layer::latchAndReleaseBuffer() {
-    if (hasReadyFrame()) {
-        bool ignored = false;
-        latchBuffer(ignored, systemTime());
-    }
-    releasePendingBuffer(systemTime());
-}
-
-PixelFormat Layer::getPixelFormat() const {
-    return mBufferInfo.mPixelFormat;
-}
-
 bool Layer::getTransformToDisplayInverse() const {
     return mBufferInfo.mTransformToDisplayInverse;
 }
@@ -3370,18 +1583,6 @@
     return mBufferInfo.mTransform;
 }
 
-ui::Dataspace Layer::getDataSpace() const {
-    return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace;
-}
-
-bool Layer::isFrontBuffered() const {
-    if (mBufferInfo.mBuffer == nullptr) {
-        return false;
-    }
-
-    return mBufferInfo.mBuffer->getUsage() & AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
-}
-
 ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) {
     ui::Dataspace updatedDataspace = dataspace;
     // translate legacy dataspaces to modern dataspaces
@@ -3417,84 +1618,6 @@
     return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
 }
 
-const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const {
-    return mBufferInfo.mBuffer;
-}
-
-bool Layer::setColor(const half3& color) {
-    if (mDrawingState.color.rgb == color) {
-        return false;
-    }
-
-    mDrawingState.sequence++;
-    mDrawingState.color.rgb = color;
-    mDrawingState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool Layer::fillsColor() const {
-    return !hasBufferOrSidebandStream() && mDrawingState.color.r >= 0.0_hf &&
-            mDrawingState.color.g >= 0.0_hf && mDrawingState.color.b >= 0.0_hf;
-}
-
-bool Layer::hasBlur() const {
-    return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
-}
-
-void Layer::updateSnapshot(bool updateGeometry) {
-    if (!getCompositionEngineLayerFE()) {
-        return;
-    }
-
-    auto* snapshot = editLayerSnapshot();
-    if (updateGeometry) {
-        prepareBasicGeometryCompositionState();
-        prepareGeometryCompositionState();
-        snapshot->roundedCorner = getRoundedCornerState();
-        snapshot->transformedBounds = mScreenBounds;
-        if (mEffectiveShadowRadius > 0.f) {
-            snapshot->shadowSettings = mFlinger->mDrawingState.globalShadowSettings;
-
-            // Note: this preserves existing behavior of shadowing the entire layer and not cropping
-            // it if transparent regions are present. This may not be necessary since shadows are
-            // typically cast by layers without transparent regions.
-            snapshot->shadowSettings.boundaries = mBounds;
-
-            const float casterAlpha = snapshot->alpha;
-            const bool casterIsOpaque =
-                    ((mBufferInfo.mBuffer != nullptr) && isOpaque(mDrawingState));
-
-            // If the casting layer is translucent, we need to fill in the shadow underneath the
-            // layer. Otherwise the generated shadow will only be shown around the casting layer.
-            snapshot->shadowSettings.casterIsTranslucent = !casterIsOpaque || (casterAlpha < 1.0f);
-            snapshot->shadowSettings.ambientColor *= casterAlpha;
-            snapshot->shadowSettings.spotColor *= casterAlpha;
-        }
-        snapshot->shadowSettings.length = mEffectiveShadowRadius;
-    }
-    snapshot->contentOpaque = isOpaque(mDrawingState);
-    snapshot->layerOpaqueFlagSet =
-            (mDrawingState.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
-    sp<Layer> p = mDrawingParent.promote();
-    if (p != nullptr) {
-        snapshot->parentTransform = p->getTransform();
-    } else {
-        snapshot->parentTransform.reset();
-    }
-    snapshot->bufferSize = getBufferSize(mDrawingState);
-    snapshot->externalTexture = mBufferInfo.mBuffer;
-    snapshot->hasReadyFrame = hasReadyFrame();
-    preparePerFrameCompositionState();
-}
-
-void Layer::updateChildrenSnapshots(bool updateGeometry) {
-    for (const sp<Layer>& child : mDrawingChildren) {
-        child->updateSnapshot(updateGeometry);
-        child->updateChildrenSnapshots(updateGeometry);
-    }
-}
-
 bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds,
                                        TrustedPresentationListener const& listener) {
     bool hadTrustedPresentationListener = hasTrustedPresentationListener();
@@ -3527,35 +1650,32 @@
     mLastLatchTime = latchTime;
 }
 
-void Layer::setIsSmallDirty(const Region& damageRegion,
-                            const ui::Transform& layerToDisplayTransform) {
-    mSmallDirty = false;
+void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) {
     if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) {
+        snapshot->isSmallDirty = false;
         return;
     }
 
     if (mWindowType != WindowInfo::Type::APPLICATION &&
         mWindowType != WindowInfo::Type::BASE_APPLICATION) {
+        snapshot->isSmallDirty = false;
         return;
     }
 
-    Rect bounds = damageRegion.getBounds();
+    Rect bounds = snapshot->surfaceDamage.getBounds();
     if (!bounds.isValid()) {
+        snapshot->isSmallDirty = false;
         return;
     }
 
     // Transform to screen space.
-    bounds = layerToDisplayTransform.transform(bounds);
+    bounds = snapshot->localTransform.transform(bounds);
 
     // If the damage region is a small dirty, this could give the hint for the layer history that
     // it could suppress the heuristic rate when calculating.
-    mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId,
-                                                         bounds.getWidth() * bounds.getHeight());
-}
-
-void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) {
-    setIsSmallDirty(snapshot->surfaceDamage, snapshot->localTransform);
-    snapshot->isSmallDirty = mSmallDirty;
+    snapshot->isSmallDirty =
+            mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId,
+                                                   bounds.getWidth() * bounds.getHeight());
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1e4f2dc..9caa20c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -43,9 +43,7 @@
 #include <scheduler/Fps.h>
 #include <scheduler/Seamlessness.h>
 
-#include <chrono>
 #include <cstdint>
-#include <list>
 #include <optional>
 #include <vector>
 
@@ -56,7 +54,6 @@
 #include "LayerVector.h"
 #include "Scheduler/LayerInfo.h"
 #include "SurfaceFlinger.h"
-#include "Tracing/LayerTracing.h"
 #include "TransactionCallbackInvoker.h"
 
 using namespace android::surfaceflinger;
@@ -97,42 +94,15 @@
         eInputInfoChanged = 0x00000004
     };
 
-    struct Geometry {
-        uint32_t w;
-        uint32_t h;
-        ui::Transform transform;
-
-        inline bool operator==(const Geometry& rhs) const {
-            return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) &&
-                    (transform.ty() == rhs.transform.ty());
-        }
-        inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
-    };
-
     using FrameRate = scheduler::LayerInfo::FrameRate;
     using FrameRateCompatibility = scheduler::FrameRateCompatibility;
     using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy;
 
     struct State {
-        int32_t z;
-        ui::LayerStack layerStack;
-        uint32_t flags;
         int32_t sequence; // changes when visible regions can change
-        bool modified;
         // Crop is expressed in layer space coordinate.
         Rect crop;
         LayerMetadata metadata;
-        // If non-null, a Surface this Surface's Z-order is interpreted relative to.
-        wp<Layer> zOrderRelativeOf;
-        bool isRelativeOf{false};
-
-        // A list of surfaces whose Z-order is interpreted relative to ours.
-        SortedVector<wp<Layer>> zOrderRelatives;
-        half4 color;
-        float cornerRadius;
-        int backgroundBlurRadius;
-        gui::WindowInfo inputInfo;
-        wp<Layer> touchableRegionCrop;
 
         ui::Dataspace dataspace;
 
@@ -154,52 +124,18 @@
         std::shared_ptr<renderengine::ExternalTexture> buffer;
         sp<Fence> acquireFence;
         std::shared_ptr<FenceTime> acquireFenceTime;
-        HdrMetadata hdrMetadata;
-        Region surfaceDamageRegion;
-        int32_t api;
         sp<NativeHandle> sidebandStream;
         mat4 colorTransform;
-        bool hasColorTransform;
-        // pointer to background color layer that, if set, appears below the buffer state layer
-        // and the buffer state layer's children.  Z order will be set to
-        // INT_MIN
-        sp<Layer> bgColorLayer;
 
         // The deque of callback handles for this frame. The back of the deque contains the most
         // recent callback handle.
         std::deque<sp<CallbackHandle>> callbackHandles;
-        bool colorSpaceAgnostic;
         nsecs_t desiredPresentTime = 0;
         bool isAutoTimestamp = true;
 
-        // Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will
-        // be rendered around the layer.
-        float shadowRadius;
-
-        // Layer regions that are made of custom materials, like frosted glass
-        std::vector<BlurRegion> blurRegions;
-
-        // Priority of the layer assigned by Window Manager.
-        int32_t frameRateSelectionPriority;
-
-        // Default frame rate compatibility used to set the layer refresh rate votetype.
-        FrameRateCompatibility defaultFrameRateCompatibility;
-        FrameRate frameRate;
-
         // The combined frame rate of parents / children of this layer
         FrameRate frameRateForLayerTree;
 
-        FrameRateSelectionStrategy frameRateSelectionStrategy;
-
-        // Set by window manager indicating the layer and all its children are
-        // in a different orientation than the display. The hint suggests that
-        // the graphic producers should receive a transform hint as if the
-        // display was in this orientation. When the display changes to match
-        // the layer orientation, the graphic producer may not need to allocate
-        // a buffer of a different size. ui::Transform::ROT_INVALID means the
-        // a fixed transform hint is not set.
-        ui::Transform::RotationFlags fixedTransformHint;
-
         // The vsync info that was used to start the transaction
         FrameTimelineInfo frameTimelineInfo;
 
@@ -219,21 +155,12 @@
         // An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
         // trigger a warning if the number of SurfaceFrames crosses the threshold.
         static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
-
-        // Stretch effect to apply to this layer
-        StretchEffect stretchEffect;
-
-        // Whether or not this layer is a trusted overlay for input
-        bool isTrustedOverlay;
         Rect bufferCrop;
         Rect destinationFrame;
         sp<IBinder> releaseBufferEndpoint;
-        gui::DropInputMode dropInputMode;
         bool autoRefresh = false;
-        bool dimmingEnabled = true;
         float currentHdrSdrRatio = 1.f;
         float desiredHdrSdrRatio = -1.f;
-        gui::CachingHint cachingHint = gui::CachingHint::Enabled;
         int64_t latchedVsyncId = 0;
         bool useVsyncIdForRefreshRateSelection = false;
     };
@@ -245,15 +172,7 @@
     static void miniDumpHeader(std::string& result);
 
     // Provide unique string for each class type in the Layer hierarchy
-    virtual const char* getType() const { return "Layer"; }
-
-    // true if this layer is visible, false otherwise
-    virtual bool isVisible() const;
-
-    // Set a 2x2 transformation matrix on the layer. This transform
-    // will be applied after parent transforms, but before any final
-    // producer specified transform.
-    bool setMatrix(const layer_state_t::matrix22_t& matrix);
+    const char* getType() const { return "Layer"; }
 
     // This second set of geometry attributes are controlled by
     // setGeometryAppliesWithResize, and their default mode is to be
@@ -261,49 +180,9 @@
     // while a resize is pending, then update of these attributes will
     // be delayed until the resize completes.
 
-    // setPosition operates in parent buffer space (pre parent-transform) or display
-    // space for top-level layers.
-    bool setPosition(float x, float y);
     // Buffer space
     bool setCrop(const Rect& crop);
 
-    // TODO(b/38182121): Could we eliminate the various latching modes by
-    // using the layer hierarchy?
-    // -----------------------------------------------------------------------
-    virtual bool setLayer(int32_t z);
-    virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
-
-    virtual bool setAlpha(float alpha);
-    bool setColor(const half3& /*color*/);
-
-    // Set rounded corner radius for this layer and its children.
-    //
-    // We only support 1 radius per layer in the hierarchy, where parent layers have precedence.
-    // The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
-    // from which we inferred the rounded corner radius.
-    virtual bool setCornerRadius(float cornerRadius);
-    // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
-    // is specified in pixels.
-    virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
-    virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
-    bool setTransparentRegionHint(const Region& transparent);
-    virtual bool setTrustedOverlay(bool);
-    virtual bool setFlags(uint32_t flags, uint32_t mask);
-    virtual bool setLayerStack(ui::LayerStack);
-    virtual ui::LayerStack getLayerStack(
-            LayerVector::StateSet state = LayerVector::StateSet::Drawing) const;
-
-    virtual bool setMetadata(const LayerMetadata& data);
-    virtual void setChildrenDrawingParent(const sp<Layer>&);
-    virtual bool setColorTransform(const mat4& matrix);
-    virtual mat4 getColorTransform() const;
-    virtual bool hasColorTransform() const;
-    virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
-    virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }
-    float getDesiredHdrSdrRatio() const { return getDrawingState().desiredHdrSdrRatio; }
-    float getCurrentHdrSdrRatio() const { return getDrawingState().currentHdrSdrRatio; }
-    gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; }
-
     bool setTransform(uint32_t /*transform*/);
     bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/);
     bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
@@ -314,111 +193,34 @@
     bool setDataspace(ui::Dataspace /*dataspace*/);
     bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio);
     bool setDesiredHdrHeadroom(float desiredRatio);
-    bool setCachingHint(gui::CachingHint cachingHint);
-    bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
-    bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
-    bool setApi(int32_t /*api*/);
     bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/,
                            const FrameTimelineInfo& /* info*/, nsecs_t /* postTime */,
                            gui::GameMode gameMode);
     bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/,
                                           bool willPresent);
-    virtual bool setColorSpaceAgnostic(const bool agnostic);
-    virtual bool setDimmingEnabled(const bool dimmingEnabled);
-    virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
-    void setAutoRefresh(bool /* autoRefresh */);
-    bool setDropInputMode(gui::DropInputMode);
 
-    ui::Dataspace getDataSpace() const;
-
-    virtual bool isFrontBuffered() const;
-
-    virtual sp<LayerFE> getCompositionEngineLayerFE() const;
-    virtual sp<LayerFE> copyCompositionEngineLayerFE() const;
     sp<LayerFE> getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
     sp<LayerFE> getOrCreateCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
 
-    const frontend::LayerSnapshot* getLayerSnapshot() const;
-    frontend::LayerSnapshot* editLayerSnapshot();
-    std::unique_ptr<frontend::LayerSnapshot> stealLayerSnapshot();
-    void updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot);
-
     // If we have received a new buffer this frame, we will pass its surface
     // damage down to hardware composer. Otherwise, we must send a region with
     // one empty rect.
-    void useSurfaceDamage();
-    void useEmptyDamage();
     Region getVisibleRegion(const DisplayDevice*) const;
     void updateLastLatchTime(nsecs_t latchtime);
 
     /*
-     * isOpaque - true if this surface is opaque
-     *
-     * This takes into account the buffer format (i.e. whether or not the
-     * pixel format includes an alpha channel) and the "opaque" flag set
-     * on the layer.  It does not examine the current plane alpha value.
-     */
-    bool isOpaque(const Layer::State&) const;
-
-    /*
-     * Returns whether this layer can receive input.
-     */
-    bool canReceiveInput() const;
-
-    /*
-     * Whether or not the layer should be considered visible for input calculations.
-     */
-    virtual bool isVisibleForInput() const {
-        // For compatibility reasons we let layers which can receive input
-        // receive input before they have actually submitted a buffer. Because
-        // of this we use canReceiveInput instead of isVisible to check the
-        // policy-visibility, ignoring the buffer state. However for layers with
-        // hasInputInfo()==false we can use the real visibility state.
-        // We are just using these layers for occlusion detection in
-        // InputDispatcher, and obviously if they aren't visible they can't occlude
-        // anything.
-        return hasInputInfo() ? canReceiveInput() : isVisible();
-    }
-
-    /*
      * isProtected - true if the layer may contain protected contents in the
      * GRALLOC_USAGE_PROTECTED sense.
      */
     bool isProtected() const;
-
-    /*
-     * isFixedSize - true if content has a fixed size
-     */
-    virtual bool isFixedSize() const { return true; }
-
     /*
      * usesSourceCrop - true if content should use a source crop
      */
     bool usesSourceCrop() const { return hasBufferOrSidebandStream(); }
 
-    // Most layers aren't created from the main thread, and therefore need to
-    // grab the SF state lock to access HWC, but ContainerLayer does, so we need
-    // to avoid grabbing the lock again to avoid deadlock
-    virtual bool isCreatedFromMainThread() const { return false; }
-
-    ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; }
-    Region getActiveTransparentRegion(const Layer::State& s) const {
-        return s.transparentRegionHint;
-    }
     Rect getCrop(const Layer::State& s) const { return s.crop; }
     bool needsFiltering(const DisplayDevice*) const;
 
-    // True if this layer requires filtering
-    // This method is distinct from needsFiltering() in how the filter
-    // requirement is computed. needsFiltering() compares displayFrame and crop,
-    // where as this method transforms the displayFrame to layer-stack space
-    // first. This method should be used if there is no physical display to
-    // project onto when taking screenshots, as the filtering requirements are
-    // different.
-    // If the parent transform needs to be undone when capturing the layer, then
-    // the inverse parent transform is also required.
-    bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const;
-
     // from graphics API
     static ui::Dataspace translateDataspace(ui::Dataspace dataspace);
     uint64_t mPreviousFrameNumber = 0;
@@ -437,8 +239,6 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/);
-
     bool latchBufferImpl(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
                          bool bgColorOnly);
 
@@ -449,14 +249,6 @@
     bool willReleaseBufferOnLatch() const;
 
     /*
-     * Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
-     * This is used if the buffer is just latched and releases to free up the buffer
-     * and will not be shown on screen.
-     * Should only be called on the main thread.
-     */
-    void latchAndReleaseBuffer();
-
-    /*
      * returns the rectangle that crops the content of the layer and scales it
      * to the layer's size.
      */
@@ -468,15 +260,6 @@
     uint32_t getBufferTransform() const;
 
     sp<GraphicBuffer> getBuffer() const;
-    const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const;
-
-    /*
-     * Returns if a frame is ready
-     */
-    bool hasReadyFrame() const;
-
-    virtual int32_t getQueuedFrameCount() const { return 0; }
-
     /**
      * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
      * any buffer transformations. Returns Rect::INVALID_RECT if the layer has no buffer or the
@@ -484,33 +267,10 @@
      */
     Rect getBufferSize(const Layer::State&) const;
 
-    /**
-     * Returns the source bounds. If the bounds are not defined, it is inferred from the
-     * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
-     * For the root layer, this is the display viewport size.
-     */
-    FloatRect computeSourceBounds(const FloatRect& parentBounds) const;
-    virtual FrameRate getFrameRateForLayerTree() const;
+    FrameRate getFrameRateForLayerTree() const;
 
     bool getTransformToDisplayInverse() const;
 
-    // Returns how rounded corners should be drawn for this layer.
-    // A layer can override its parent's rounded corner settings if the parent's rounded
-    // corner crop does not intersect with its own rounded corner crop.
-    virtual frontend::RoundedCornerState getRoundedCornerState() const;
-
-    bool hasRoundedCorners() const { return getRoundedCornerState().hasRoundedCorners(); }
-
-    PixelFormat getPixelFormat() const;
-    /**
-     * Return whether this layer needs an input info. We generate InputWindowHandles for all
-     * non-cursor buffered layers regardless of whether they have an InputChannel. This is to enable
-     * the InputDispatcher to do PID based occlusion detection.
-     */
-    bool needsInputInfo() const {
-        return (hasInputInfo() || hasBufferOrSidebandStream()) && !mPotentialCursor;
-    }
-
     // Implements RefBase.
     void onFirstRef() override;
 
@@ -521,17 +281,11 @@
         uint32_t mTransform{0};
         ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
         Rect mCrop;
-        uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
-        Region mSurfaceDamage;
-        HdrMetadata mHdrMetadata;
-        int mApi;
         PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
         bool mTransformToDisplayInverse{false};
-
         std::shared_ptr<renderengine::ExternalTexture> mBuffer;
         uint64_t mFrameNumber;
         sp<IBinder> mReleaseBufferEndpoint;
-
         bool mFrameLatencyNeeded{false};
         float mDesiredHdrSdrRatio = -1.f;
     };
@@ -539,8 +293,6 @@
     BufferInfo mBufferInfo;
     std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel;
 
-    // implements compositionengine::LayerFE
-    const compositionengine::LayerFECompositionState* getCompositionState() const;
     bool fenceHasSignaled() const;
     void onPreComposition(nsecs_t refreshStartTime);
     void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack,
@@ -561,15 +313,6 @@
 
     const char* getDebugName() const;
 
-    bool setShadowRadius(float shadowRadius);
-
-    // Before color management is introduced, contents on Android have to be
-    // desaturated in order to match what they appears like visually.
-    // With color management, these contents will appear desaturated, thus
-    // needed to be saturated so that they match what they are designed for
-    // visually.
-    bool isLegacyDataSpace() const;
-
     uint32_t getTransactionFlags() const { return mTransactionFlags; }
 
     static bool computeTrustedPresentationState(const FloatRect& bounds,
@@ -592,14 +335,6 @@
     // Clears and returns the masked bits.
     uint32_t clearTransactionFlags(uint32_t mask);
 
-    FloatRect getBounds(const Region& activeTransparentRegion) const;
-    FloatRect getBounds() const;
-    Rect getInputBoundsInDisplaySpace(const FloatRect& insetBounds,
-                                      const ui::Transform& displayTransform);
-
-    // Compute bounds for the layer and cache the results.
-    void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius);
-
     int32_t getSequence() const { return sequence; }
 
     // For tracing.
@@ -610,90 +345,35 @@
     // only used within a single layer.
     uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; }
 
-    /*
-     * isSecure - true if this surface is secure, that is if it prevents
-     * screenshots or VNC servers. A surface can be set to be secure by the
-     * application, being secure doesn't mean the surface has DRM contents.
-     */
-    bool isSecure() const;
-
-    /*
-     * isHiddenByPolicy - true if this layer has been forced invisible.
-     * just because this is false, doesn't mean isVisible() is true.
-     * For example if this layer has no active buffer, it may not be hidden by
-     * policy, but it still can not be visible.
-     */
-    bool isHiddenByPolicy() const;
-
-    // True if the layer should be skipped in screenshots, screen recordings,
-    // and mirroring to external or virtual displays.
-    bool isInternalDisplayOverlay() const;
-
-    ui::LayerFilter getOutputFilter() const {
-        return {getLayerStack(), isInternalDisplayOverlay()};
-    }
-
-    perfetto::protos::LayerProto* writeToProto(perfetto::protos::LayersProto& layersProto,
-                                               uint32_t traceFlags);
     void writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
                                       ui::LayerStack layerStack);
 
-    // Write states that are modified by the main thread. This includes drawing
-    // state as well as buffer data. This should be called in the main or tracing
-    // thread.
-    void writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo);
-    // Write drawing or current state. If writing current state, the caller should hold the
-    // external mStateLock. If writing drawing state, this function should be called on the
-    // main or tracing thread.
-    void writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo, LayerVector::StateSet,
-                                 uint32_t traceFlags = LayerTracing::TRACE_ALL);
-
     gui::WindowInfo::Type getWindowType() const { return mWindowType; }
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
      * out which attributes of the surface have changed.
      */
-    virtual uint32_t doTransaction(uint32_t transactionFlags);
-
-    /*
-     * Remove relative z for the layer if its relative parent is not part of the
-     * provided layer tree.
-     */
-    void removeRelativeZ(const std::vector<Layer*>& layersInTree);
+    uint32_t doTransaction(uint32_t transactionFlags);
 
     inline const State& getDrawingState() const { return mDrawingState; }
     inline State& getDrawingState() { return mDrawingState; }
 
     void miniDump(std::string& result, const frontend::LayerSnapshot&, const DisplayDevice&) const;
     void dumpFrameStats(std::string& result) const;
-    void dumpOffscreenDebugInfo(std::string& result) const;
     void clearFrameStats();
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
     void onDisconnect();
 
     ui::Transform getTransform() const;
-    bool isTransformValid() const;
 
-    // Returns the Alpha of the Surface, accounting for the Alpha
-    // of parent Surfaces in the hierarchy (alpha's will be multiplied
-    // down the hierarchy).
-    half getAlpha() const;
     half4 getColor() const;
     int32_t getBackgroundBlurRadius() const;
     bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
 
-    // Returns the transform hint set by Window Manager on the layer or one of its parents.
-    // This traverses the current state because the data is needed when creating
-    // the layer(off drawing thread) and the hint should be available before the producer
-    // is ready to acquire a buffer.
-    ui::Transform::RotationFlags getFixedTransformHint() const;
-
     bool isHandleAlive() const { return mHandleAlive; }
     bool onHandleDestroyed() { return mHandleAlive = false; }
-    Rect getScreenBounds(bool reduceTransparentRegion = true) const;
-    int32_t getZ(LayerVector::StateSet) const;
 
     /**
      * Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
@@ -703,7 +383,7 @@
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
 
-    virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
+    void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
     void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime,
                                                    gui::GameMode gameMode);
     void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
@@ -732,31 +412,14 @@
     // this to be called once.
     sp<IBinder> getHandle();
     const std::string& getName() const { return mName; }
-    bool getPremultipledAlpha() const;
     void setInputInfo(const gui::WindowInfo& info);
 
-    struct InputDisplayArgs {
-        const ui::Transform* transform = nullptr;
-        bool isSecure = false;
-    };
-    gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs);
-
-    /**
-     * Returns whether this layer has an explicitly set input-info.
-     */
-    bool hasInputInfo() const;
-
     virtual uid_t getOwnerUid() const { return mOwnerUid; }
 
     pid_t getOwnerPid() { return mOwnerPid; }
 
     int32_t getOwnerAppId() { return mOwnerAppId; }
 
-    mutable bool contentDirty{false};
-    Region surfaceDamageRegion;
-
-    // True when the surfaceDamageRegion is recognized as a small area update.
-    bool mSmallDirty{false};
     // Used to check if mUsedVsyncIdForRefreshRateSelection should be expired when it stop updating.
     nsecs_t mMaxTimeForUseVsyncId = 0;
     // True when DrawState.useVsyncIdForRefreshRateSelection previously set to true during updating
@@ -770,35 +433,11 @@
 
     bool mPendingHWCDestroy{false};
 
-    bool backpressureEnabled() const {
-        return mDrawingState.flags & layer_state_t::eEnableBackpressure;
-    }
-
-    bool setStretchEffect(const StretchEffect& effect);
-
     bool setBufferCrop(const Rect& /* bufferCrop */);
-    bool setDestinationFrame(const Rect& /* destinationFrame */);
     // See mPendingBufferTransactions
     void decrementPendingBufferCount();
     std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; }
     std::string getPendingBufferCounterName() { return mBlastTransactionName; }
-    bool updateGeometry();
-
-    bool isSimpleBufferUpdate(const layer_state_t& s) const;
-
-    static bool isOpaqueFormat(PixelFormat format);
-
-    // Updates the LayerSnapshot. This must be called prior to sending layer data to
-    // CompositionEngine or RenderEngine (i.e. before calling CompositionEngine::present or
-    // LayerFE::prepareClientComposition).
-    //
-    // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through
-    // CompositionEngine to create a single path for composing layers.
-    void updateSnapshot(bool updateGeometry);
-    void updateChildrenSnapshots(bool updateGeometry);
-
-    bool willPresentCurrentTransaction() const;
-
     void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
                                    const sp<GraphicBuffer>& buffer, uint64_t framenumber,
                                    const sp<Fence>& releaseFence);
@@ -844,7 +483,6 @@
     const sp<SurfaceFlinger> mFlinger;
 
     // Check if the damage region is a small dirty.
-    void setIsSmallDirty(const Region& damageRegion, const ui::Transform& layerToDisplayTransform);
     void setIsSmallDirty(frontend::LayerSnapshot* snapshot);
 
 protected:
@@ -856,52 +494,16 @@
     friend class TransactionFrameTracerTest;
     friend class TransactionSurfaceFrameTest;
 
-    void preparePerFrameCompositionState();
-    void preparePerFrameBufferCompositionState();
-    void preparePerFrameEffectsCompositionState();
     void gatherBufferInfo();
 
-    void prepareBasicGeometryCompositionState();
-    void prepareGeometryCompositionState();
-    void prepareCursorCompositionState();
-
-    uint32_t getEffectiveUsage(uint32_t usage) const;
-
-    /**
-     * Setup rounded corners coordinates of this layer, taking into account the layer bounds and
-     * crop coordinates, transforming them into layer space.
-     */
-    void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
-    void setParent(const sp<Layer>&);
-    LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers);
-    void addZOrderRelative(const wp<Layer>& relative);
-    void removeZOrderRelative(const wp<Layer>& relative);
     compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const;
     compositionengine::OutputLayer* findOutputLayerForDisplay(
             const DisplayDevice*, const frontend::LayerHierarchy::TraversalPath& path) const;
-    bool usingRelativeZ(LayerVector::StateSet) const;
 
-    virtual ui::Transform getInputTransform() const;
-    /**
-     * Get the bounds in layer space within which this layer can receive input.
-     *
-     * These bounds are used to:
-     * - Determine the input frame for the layer to be used for occlusion detection; and
-     * - Determine the coordinate space within which the layer will receive input. The top-left of
-     *   this rect will be the origin of the coordinate space that the input events sent to the
-     *   layer will be in (prior to accounting for surface insets).
-     *
-     * The layer can still receive touch input if these bounds are invalid if
-     * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input
-     * in this layer's space, regardless of the specified crop layer.
-     */
-    std::pair<FloatRect, bool> getInputBounds(bool fillParentBounds) const;
-
-    bool mPremultipliedAlpha{true};
     const std::string mName;
     const std::string mTransactionName{"TX - " + mName};
 
-    // These are only accessed by the main thread or the tracing thread.
+    // These are only accessed by the main thread.
     State mDrawingState;
 
     TrustedPresentationThresholds mTrustedPresentationThresholds;
@@ -921,34 +523,16 @@
 
     // main thread
     sp<NativeHandle> mSidebandStream;
-    // False if the buffer and its contents have been previously used for GPU
-    // composition, true otherwise.
-    bool mIsActiveBufferUpdatedForGpu = true;
 
     // We encode unset as -1.
     std::atomic<uint64_t> mCurrentFrameNumber{0};
-    // Whether filtering is needed b/c of the drawingstate
-    bool mNeedsFiltering{false};
-
-    std::atomic<bool> mRemovedFromDrawingState{false};
-
-    // page-flip thread (currently main thread)
-    bool mProtectedByApp{false}; // application requires protected path to external sink
 
     // protected by mLock
     mutable Mutex mLock;
 
-    const wp<Client> mClientRef;
-
     // This layer can be a cursor on some displays.
     bool mPotentialCursor{false};
 
-    LayerVector mCurrentChildren{LayerVector::StateSet::Current};
-    LayerVector mDrawingChildren{LayerVector::StateSet::Drawing};
-
-    wp<Layer> mCurrentParent;
-    wp<Layer> mDrawingParent;
-
     // Window types from WindowManager.LayoutParams
     const gui::WindowInfo::Type mWindowType;
 
@@ -966,8 +550,6 @@
     // Used in buffer stuffing analysis in FrameTimeline.
     nsecs_t mLastLatchTime = 0;
 
-    mutable bool mDrawingStateModified = false;
-
     sp<Fence> mLastClientCompositionFence;
     bool mClearClientCompositionFenceOnLayerDisplayed = false;
 private:
@@ -979,44 +561,20 @@
     friend class TransactionFrameTracerTest;
     friend class TransactionSurfaceFrameTest;
 
-    bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
     bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
 
     std::atomic<bool> mSidebandStreamChanged{false};
 
-    // Returns true if the layer can draw shadows on its border.
-    virtual bool canDrawShadows() const { return true; }
-
     aidl::android::hardware::graphics::composer3::Composition getCompositionType(
             const DisplayDevice&) const;
     aidl::android::hardware::graphics::composer3::Composition getCompositionType(
             const compositionengine::OutputLayer*) const;
 
-    bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overrideChildren,
-                                        bool* transactionNeeded);
-    void setZOrderRelativeOf(const wp<Layer>& relativeOf);
-    bool isTrustedOverlay() const;
-    gui::DropInputMode getDropInputMode() const;
-    void handleDropInputMode(gui::WindowInfo& info) const;
-
-    // Finds the top most layer in the hierarchy. This will find the root Layer where the parent is
-    // null.
-    sp<Layer> getRootLayer();
-
-    // Fills in the touch occlusion mode of the first parent (including this layer) that
-    // hasInputInfo() or no-op if no such parent is found.
-    void fillTouchOcclusionMode(gui::WindowInfo& info);
-
-    // Fills in the frame and transform info for the gui::WindowInfo.
-    void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay);
-
     inline void tracePendingBufferCount(int32_t pendingBuffers);
 
     // Latch sideband stream and returns true if the dirty region should be updated.
     bool latchSidebandStream(bool& recomputeVisibleRegions);
 
-    bool hasFrameUpdate() const;
-
     void updateTexImage(nsecs_t latchTime, bool bgColorOnly = false);
 
     // Crop that applies to the buffer
@@ -1027,15 +585,6 @@
                                    const sp<Fence>& releaseFence,
                                    uint32_t currentMaxAcquiredBufferCount);
 
-    // Returns true if the transformed buffer size does not match the layer size and we need
-    // to apply filtering.
-    bool bufferNeedsFiltering() const;
-
-    // Returns true if there is a valid color to fill.
-    bool fillsColor() const;
-    // Returns true if this layer has a blur value.
-    bool hasBlur() const;
-    bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); }
     bool hasBufferOrSidebandStream() const {
         return ((mSidebandStream != nullptr) || (mBufferInfo.mBuffer != nullptr));
     }
@@ -1044,33 +593,6 @@
         return ((mDrawingState.sidebandStream != nullptr) || (mDrawingState.buffer != nullptr));
     }
 
-    bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); }
-
-    bool shouldOverrideChildrenFrameRate() const {
-        return getDrawingState().frameRateSelectionStrategy ==
-                FrameRateSelectionStrategy::OverrideChildren;
-    }
-
-    bool shouldPropagateFrameRate() const {
-        return getDrawingState().frameRateSelectionStrategy != FrameRateSelectionStrategy::Self;
-    }
-
-    // Cached properties computed from drawing state
-    // Effective transform taking into account parent transforms and any parent scaling, which is
-    // a transform from the current layer coordinate space to display(screen) coordinate space.
-    ui::Transform mEffectiveTransform;
-
-    // Bounds of the layer before any transformation is applied and before it has been cropped
-    // by its parents.
-    FloatRect mSourceBounds;
-
-    // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and
-    // its parent bounds.
-    FloatRect mBounds;
-
-    // Layer bounds in screen space.
-    FloatRect mScreenBounds;
-
     bool mGetHandleCalled = false;
 
     // The inherited shadow radius after taking into account the layer hierarchy. This is the
@@ -1081,15 +603,10 @@
     // Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats.
     gui::GameMode mGameMode = gui::GameMode::Unsupported;
 
-    // A list of regions on this layer that should have blurs.
-    const std::vector<BlurRegion> getBlurRegions() const;
-
     bool mIsAtRoot = false;
 
     uint32_t mLayerCreationFlags;
 
-    bool findInHierarchy(const sp<Layer>&);
-
     void releasePreviousBuffer();
     void resetDrawingStateBufferInfo();
 
@@ -1122,10 +639,7 @@
     // not specify a destination frame.
     ui::Transform mRequestedTransform;
 
-    sp<LayerFE> mLegacyLayerFE;
     std::vector<std::pair<frontend::LayerHierarchy::TraversalPath, sp<LayerFE>>> mLayerFEs;
-    std::unique_ptr<frontend::LayerSnapshot> mSnapshot =
-            std::make_unique<frontend::LayerSnapshot>();
     bool mHandleAlive = false;
 };
 
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 885c3d3..5eea45b 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -178,7 +178,7 @@
 }
 
 void LayerProtoHelper::writeToProto(
-        const WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+        const WindowInfo& inputInfo,
         std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto) {
     if (inputInfo.token == nullptr) {
         return;
@@ -208,13 +208,6 @@
     proto->set_global_scale_factor(inputInfo.globalScaleFactor);
     LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform());
     proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop);
-    auto cropLayer = touchableRegionBounds.promote();
-    if (cropLayer != nullptr) {
-        proto->set_crop_layer_id(cropLayer->sequence);
-        LayerProtoHelper::writeToProto(cropLayer->getScreenBounds(
-                                               false /* reduceTransparentRegion */),
-                                       [&]() { return proto->mutable_touchable_region_crop(); });
-    }
 }
 
 void LayerProtoHelper::writeToProto(const mat4 matrix,
@@ -482,7 +475,7 @@
     layerInfo->set_owner_uid(requestedState.ownerUid.val());
 
     if ((traceFlags & LayerTracing::TRACE_INPUT) && snapshot.hasInputInfo()) {
-        LayerProtoHelper::writeToProto(snapshot.inputInfo, {},
+        LayerProtoHelper::writeToProto(snapshot.inputInfo,
                                        [&]() { return layerInfo->mutable_input_window_info(); });
     }
 
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index c0198b6..41ea684 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -62,7 +62,7 @@
             const renderengine::ExternalTexture& buffer,
             std::function<perfetto::protos::ActiveBufferProto*()> getActiveBufferProto);
     static void writeToProto(
-            const gui::WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+            const gui::WindowInfo& inputInfo,
             std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto);
     static void writeToProto(const mat4 matrix,
                              perfetto::protos::ColorTransformProto* colorTransformProto);
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index ff0a955..13e054e 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -45,16 +45,6 @@
     const auto& lState = l->getDrawingState();
     const auto& rState = r->getDrawingState();
 
-    const auto ls = lState.layerStack;
-    const auto rs = rState.layerStack;
-    if (ls != rs)
-        return (ls > rs) ? 1 : -1;
-
-    int32_t lz = lState.z;
-    int32_t rz = rState.z;
-    if (lz != rz)
-        return (lz > rz) ? 1 : -1;
-
     if (l->sequence == r->sequence)
         return 0;
 
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 034e467..aa66ccf 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -39,21 +39,6 @@
             mReqDataSpace(reqDataSpace),
             mCaptureFill(captureFill) {}
 
-    static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
-            std::function<void(const LayerVector::Visitor&)> traverseLayers) {
-        return [traverseLayers = std::move(traverseLayers)]() {
-            std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
-            traverseLayers([&](Layer* layer) {
-                // Layer::prepareClientComposition uses the layer's snapshot to populate the
-                // resulting LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings
-                // are generated with the layer's current buffer and geometry.
-                layer->updateSnapshot(true /* updateGeometry */);
-                layers.emplace_back(layer, layer->copyCompositionEngineLayerFE());
-            });
-            return layers;
-        };
-    }
-
     virtual ~RenderArea() = default;
 
     // Returns true if the render area is secure.  A secure layer should be
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index d31fcea..218c56e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -320,7 +320,8 @@
 
     mVsyncRegistration.update({.workDuration = mWorkDuration.get().count(),
                                .readyDuration = mReadyDuration.count(),
-                               .lastVsync = mLastVsyncCallbackTime.ns()});
+                               .lastVsync = mLastVsyncCallbackTime.ns(),
+                               .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
 }
 
 sp<EventThreadConnection> EventThread::createEventConnection(
@@ -527,10 +528,11 @@
         }
 
         if (mState == State::VSync) {
-            const auto scheduleResult =
-                    mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
-                                                 .readyDuration = mReadyDuration.count(),
-                                                 .lastVsync = mLastVsyncCallbackTime.ns()});
+            const auto scheduleResult = mVsyncRegistration.schedule(
+                    {.workDuration = mWorkDuration.get().count(),
+                     .readyDuration = mReadyDuration.count(),
+                     .lastVsync = mLastVsyncCallbackTime.ns(),
+                     .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
             LOG_ALWAYS_FATAL_IF(!scheduleResult, "Error scheduling callback");
         } else {
             mVsyncRegistration.cancel();
@@ -725,8 +727,9 @@
     }
     if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
         FlagManager::getInstance().vrr_config()) {
-        mCallback.onExpectedPresentTimePosted(
-                TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime()));
+        mLastCommittedVsyncTime =
+                TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime());
+        mCallback.onExpectedPresentTimePosted(mLastCommittedVsyncTime);
     }
 }
 
@@ -744,9 +747,12 @@
 
     const auto relativeLastCallTime =
             ticks<std::milli, float>(mLastVsyncCallbackTime - TimePoint::now());
+    const auto relativeLastCommittedTime =
+            ticks<std::milli, float>(mLastCommittedVsyncTime - TimePoint::now());
     StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
                   mWorkDuration.get().count() / 1e6f, mReadyDuration.count() / 1e6f);
     StringAppendF(&result, "%.2fms relative to now\n", relativeLastCallTime);
+    StringAppendF(&result, " with vsync committed at %.2fms", relativeLastCommittedTime);
 
     StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
     for (const auto& event : mPendingEvents) {
@@ -794,7 +800,8 @@
     if (reschedule) {
         mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
                                      .readyDuration = mReadyDuration.count(),
-                                     .lastVsync = mLastVsyncCallbackTime.ns()});
+                                     .lastVsync = mLastVsyncCallbackTime.ns(),
+                                     .committedVsyncOpt = mLastCommittedVsyncTime.ns()});
     }
     return oldRegistration;
 }
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index f772126..bbe4f9d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -220,6 +220,7 @@
     std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex);
     std::shared_ptr<scheduler::VsyncSchedule> mVsyncSchedule GUARDED_BY(mMutex);
     TimePoint mLastVsyncCallbackTime GUARDED_BY(mMutex) = TimePoint::now();
+    TimePoint mLastCommittedVsyncTime GUARDED_BY(mMutex) = TimePoint::now();
     scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex);
     frametimeline::TokenManager* const mTokenManager;
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index dbc458c..ff1926e 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -595,8 +595,7 @@
         return true;
     }
 
-    if (FlagManager::getInstance().view_set_requested_frame_rate_mrr() &&
-        category == FrameRateCategory::NoPreference && vote.rate.isValid() &&
+    if (category == FrameRateCategory::NoPreference && vote.rate.isValid() &&
         vote.type == FrameRateCompatibility::ExactOrMultiple) {
         return true;
     }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 9f6eab2..28fa036 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -841,7 +841,8 @@
         return score.overallScore == 0;
     });
 
-    if (policy->primaryRangeIsSingleRate()) {
+    // TODO(b/364651864): Evaluate correctness of primaryRangeIsSingleRate.
+    if (!mIsVrrDevice.load() && policy->primaryRangeIsSingleRate()) {
         // If we never scored any layers, then choose the rate from the primary
         // range instead of picking a random score from the app range.
         if (noLayerScore) {
@@ -887,8 +888,8 @@
         const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
         using fps_approx_ops::operator<;
 
-        if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
-            ALOGV("Touch Boost");
+        if (scores.front().frameRateMode.fps <= touchRefreshRates.front().frameRateMode.fps) {
+            ALOGV("Touch Boost [late]");
             SFTRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
                                    to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
             return {touchRefreshRates, GlobalSignals{.touch = true}};
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 0c43ffb..8993c38 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -93,6 +93,8 @@
      *                 readyDuration will typically be 0.
      * @lastVsync: The targeted display time. This will be snapped to the closest
      *                 predicted vsync time after lastVsync.
+     * @committedVsyncOpt: The display time that is committed to the callback as the
+     *                 target vsync time.
      *
      * callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
      * event.
@@ -101,10 +103,11 @@
         nsecs_t workDuration = 0;
         nsecs_t readyDuration = 0;
         nsecs_t lastVsync = 0;
+        std::optional<nsecs_t> committedVsyncOpt;
 
         bool operator==(const ScheduleTiming& other) const {
             return workDuration == other.workDuration && readyDuration == other.readyDuration &&
-                    lastVsync == other.lastVsync;
+                    lastVsync == other.lastVsync && committedVsyncOpt == other.committedVsyncOpt;
         }
 
         bool operator!=(const ScheduleTiming& other) const { return !(*this == other); }
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 900bce0..1925f11 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -103,7 +103,8 @@
             tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
                                                           now + timing.workDuration +
                                                                   timing.readyDuration),
-                                                 timing.lastVsync);
+                                                 timing.committedVsyncOpt.value_or(
+                                                         timing.lastVsync));
     auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
 
     bool const wouldSkipAVsyncTarget =
@@ -208,9 +209,12 @@
         const auto workDelta = mWorkloadUpdateInfo->workDuration - mScheduleTiming.workDuration;
         const auto readyDelta = mWorkloadUpdateInfo->readyDuration - mScheduleTiming.readyDuration;
         const auto lastVsyncDelta = mWorkloadUpdateInfo->lastVsync - mScheduleTiming.lastVsync;
+        const auto lastCommittedVsyncDelta =
+                mWorkloadUpdateInfo->committedVsyncOpt.value_or(mWorkloadUpdateInfo->lastVsync) -
+                mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync);
         SFTRACE_FORMAT_INSTANT("Workload updated workDelta=%" PRId64 " readyDelta=%" PRId64
-                               " lastVsyncDelta=%" PRId64,
-                               workDelta, readyDelta, lastVsyncDelta);
+                               " lastVsyncDelta=%" PRId64 " committedVsyncDelta=%" PRId64,
+                               workDelta, readyDelta, lastVsyncDelta, lastCommittedVsyncDelta);
         mScheduleTiming = *mWorkloadUpdateInfo;
         mWorkloadUpdateInfo.reset();
     }
@@ -261,10 +265,14 @@
     StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
                   mRunning ? "(in callback function)" : "", armedInfo.c_str());
     StringAppendF(&result,
-                  "\t\t\tworkDuration: %.2fms readyDuration: %.2fms lastVsync: %.2fms relative "
-                  "to now\n",
+                  "\t\t\tworkDuration: %.2fms readyDuration: %.2fms "
+                  "lastVsync: %.2fms relative to now "
+                  "committedVsync: %.2fms relative to now\n",
                   mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
-                  (mScheduleTiming.lastVsync - systemTime()) / 1e6f);
+                  (mScheduleTiming.lastVsync - systemTime()) / 1e6f,
+                  (mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync) -
+                   systemTime()) /
+                          1e6f);
 
     if (mLastDispatchTime) {
         StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 4a7cff5..6e36f02 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -695,9 +695,12 @@
         if (lastFrameMissed) {
             // If the last frame missed is the last vsync, we already shifted the timeline. Depends
             // on whether we skipped the frame (onFrameMissed) or not (onFrameBegin) we apply a
-            // different fixup. There is no need to to shift the vsync timeline again.
-            vsyncTime += missedVsync.fixup.ns();
-            SFTRACE_FORMAT_INSTANT("lastFrameMissed");
+            // different fixup if we are violating the minFramePeriod.
+            // There is no need to shift the vsync timeline again.
+            if (vsyncTime - missedVsync.vsync.ns() < minFramePeriodOpt->ns()) {
+                vsyncTime += missedVsync.fixup.ns();
+                SFTRACE_FORMAT_INSTANT("lastFrameMissed");
+            }
         } else if (mightBackpressure && lastVsyncOpt) {
             if (!FlagManager::getInstance().vrr_bugfix_24q4()) {
                 // lastVsyncOpt does not need to be corrected with the new rate, and
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f4bff8f..e98dc5c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -532,9 +532,6 @@
     mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
 
     // These are set by the HWC implementation to indicate that they will use the workarounds.
-    mIsHotplugErrViaNegVsync =
-            base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false);
-
     mIsHdcpViaNegVsync = base::GetBoolProperty("debug.sf.hwc_hdcp_via_neg_vsync"s, false);
 }
 
@@ -2172,21 +2169,13 @@
                                         std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
     if (FlagManager::getInstance().connected_display() && timestamp < 0 &&
         vsyncPeriod.has_value()) {
-        // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32
-        if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) {
-            const auto errorCode = static_cast<int32_t>(-timestamp);
-            ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
-            mScheduler->dispatchHotplugError(errorCode);
-            return;
-        }
-
         if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) {
             const int32_t value = static_cast<int32_t>(-timestamp);
             // one byte is good enough to encode android.hardware.drm.HdcpLevel
             const int32_t maxLevel = (value >> 8) & 0xFF;
             const int32_t connectedLevel = value & 0xFF;
-            ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for display %" PRIu64, __func__,
-                  connectedLevel, maxLevel, hwcDisplayId);
+            ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64,
+                  __func__, connectedLevel, maxLevel, hwcDisplayId);
             updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
             return;
         }
@@ -2226,7 +2215,7 @@
     if (FlagManager::getInstance().hotplug2()) {
         // TODO(b/311403559): use enum type instead of int
         const auto errorCode = static_cast<int32_t>(event);
-        ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId);
+        ALOGD("%s: Hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, hwcDisplayId);
         mScheduler->dispatchHotplugError(errorCode);
     }
 }
@@ -2276,6 +2265,18 @@
     }));
 }
 
+void SurfaceFlinger::onComposerHalHdcpLevelsChanged(hal::HWDisplayId hwcDisplayId,
+                                                    const HdcpLevels& levels) {
+    if (FlagManager::getInstance().hdcp_level_hal()) {
+        // TODO(b/362270040): propagate enum constants
+        const int32_t maxLevel = static_cast<int32_t>(levels.maxLevel);
+        const int32_t connectedLevel = static_cast<int32_t>(levels.connectedLevel);
+        ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64, __func__,
+              connectedLevel, maxLevel, hwcDisplayId);
+        updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel);
+    }
+}
+
 void SurfaceFlinger::configure() {
     Mutex::Autolock lock(mStateLock);
     if (configureLocked()) {
@@ -2738,7 +2739,8 @@
     if (!FlagManager::getInstance().ce_fence_promise()) {
         refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
         for (auto& [layer, _] : mLayersWithQueuedFrames) {
-            if (const auto& layerFE = layer->getCompositionEngineLayerFE())
+            if (const auto& layerFE = layer->getCompositionEngineLayerFE(
+                        {static_cast<uint32_t>(layer->sequence)}))
                 refreshArgs.layersWithQueuedFrames.push_back(layerFE);
         }
     }
@@ -2814,7 +2816,8 @@
 
         refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
         for (auto& [layer, _] : mLayersWithQueuedFrames) {
-            if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
+            if (const auto& layerFE = layer->getCompositionEngineLayerFE(
+                        {static_cast<uint32_t>(layer->sequence)})) {
                 refreshArgs.layersWithQueuedFrames.push_back(layerFE);
                 // Some layers are not displayed and do not yet have a future release fence
                 if (layerFE->getReleaseFencePromiseStatus() ==
@@ -3910,7 +3913,6 @@
     // Commit display transactions.
     const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
     mFrontEndDisplayInfosChanged = displayTransactionNeeded;
-    mForceTransactionDisplayChange = displayTransactionNeeded;
 
     if (mSomeChildrenChanged) {
         mVisibleRegionsDirty = true;
@@ -4231,6 +4233,8 @@
             if (data.hintStatus.compare_exchange_strong(scheduleHintOnTx,
                                                         NotifyExpectedPresentHintStatus::Sent)) {
                 sendHint();
+                constexpr bool kAllowToEnable = true;
+                mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable);
             }
         }));
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 414088e..7e137c8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -135,6 +135,7 @@
 class ScreenCapturer;
 class WindowInfosListenerInvoker;
 
+using ::aidl::android::hardware::drm::HdcpLevels;
 using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
 using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
 using frontend::TransactionHandler;
@@ -671,6 +672,7 @@
     void onComposerHalSeamlessPossible(hal::HWDisplayId) override;
     void onComposerHalVsyncIdle(hal::HWDisplayId) override;
     void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override;
+    void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) override;
 
     // ICompositor overrides:
     void configure() override REQUIRES(kMainThreadContext);
@@ -1228,7 +1230,6 @@
     // TODO: Also move visibleRegions over to a boolean system.
     bool mUpdateInputInfo = false;
     bool mSomeChildrenChanged;
-    bool mForceTransactionDisplayChange = false;
     bool mUpdateAttachedChoreographer = false;
 
     struct LayerIntHash {
@@ -1259,7 +1260,6 @@
     };
 
     bool mIsHdcpViaNegVsync = false;
-    bool mIsHotplugErrViaNegVsync = false;
 
     std::mutex mHotplugMutex;
     std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex);
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 8ec908f..82aa557 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -119,7 +119,6 @@
     DUMP_READ_ONLY_FLAG(connected_display);
     DUMP_READ_ONLY_FLAG(enable_small_area_detection);
     DUMP_READ_ONLY_FLAG(frame_rate_category_mrr);
-    DUMP_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr);
     DUMP_READ_ONLY_FLAG(misc1);
     DUMP_READ_ONLY_FLAG(vrr_config);
     DUMP_READ_ONLY_FLAG(hotplug2);
@@ -224,8 +223,6 @@
 FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "")
 FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "")
 FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr")
-FLAG_MANAGER_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr,
-                            "debug.sf.view_set_requested_frame_rate_mrr")
 FLAG_MANAGER_READ_ONLY_FLAG(misc1, "")
 FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config")
 FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 473e564..6619975 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -56,7 +56,6 @@
     /// Trunk stable readonly flags ///
     bool connected_display() const;
     bool frame_rate_category_mrr() const;
-    bool view_set_requested_frame_rate_mrr() const;
     bool enable_small_area_detection() const;
     bool misc1() const;
     bool vrr_config() const;
diff --git a/services/surfaceflinger/tests/OWNERS b/services/surfaceflinger/tests/OWNERS
index 56f2f1b..7857961 100644
--- a/services/surfaceflinger/tests/OWNERS
+++ b/services/surfaceflinger/tests/OWNERS
@@ -4,5 +4,5 @@
 per-file Layer* = set noparent
 per-file Layer* = pdwilliams@google.com, vishnun@google.com, melodymhsu@google.com
 
-per-file LayerHistoryTest.cpp = file:/services/surfaceflinger/OWNERS
+per-file LayerHistoryIntegrationTest.cpp = file:/services/surfaceflinger/OWNERS
 per-file LayerInfoTest.cpp = file:/services/surfaceflinger/OWNERS
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 3104dd4..ae380ad 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -515,6 +515,23 @@
         mLifecycleManager.applyTransactions(transactions);
     }
 
+    void setEdgeExtensionEffect(uint32_t id, int edge) {
+        std::vector<TransactionState> transactions;
+        transactions.emplace_back();
+        transactions.back().states.push_back({});
+
+        transactions.back().states.front().layerId = id;
+        transactions.back().states.front().state.what |= layer_state_t::eEdgeExtensionChanged;
+        transactions.back().states.front().state.edgeExtensionParameters =
+                gui::EdgeExtensionParameters();
+        transactions.back().states.front().state.edgeExtensionParameters.extendLeft = edge & LEFT;
+        transactions.back().states.front().state.edgeExtensionParameters.extendRight = edge & RIGHT;
+        transactions.back().states.front().state.edgeExtensionParameters.extendTop = edge & TOP;
+        transactions.back().states.front().state.edgeExtensionParameters.extendBottom =
+                edge & BOTTOM;
+        mLifecycleManager.applyTransactions(transactions);
+    }
+
 private:
     LayerLifecycleManager& mLifecycleManager;
 };
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 2cff2f2..6030427 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -58,6 +58,7 @@
 
 using Hwc2::Config;
 
+using ::aidl::android::hardware::drm::HdcpLevels;
 using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent;
 using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
 using hal::IComposerClient;
@@ -454,6 +455,8 @@
     MOCK_METHOD1(onComposerHalSeamlessPossible, void(hal::HWDisplayId));
     MOCK_METHOD1(onComposerHalVsyncIdle, void(hal::HWDisplayId));
     MOCK_METHOD(void, onRefreshRateChangedDebug, (const RefreshRateChangedDebugData&), (override));
+    MOCK_METHOD(void, onComposerHalHdcpLevelsChanged, (hal::HWDisplayId, const HdcpLevels&),
+                (override));
 };
 
 struct HWComposerSetCallbackTest : HWComposerTest {
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index 7e84408..de37b63 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -894,7 +894,6 @@
 
 TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithFixedSourceAndNoPreferenceCategory) {
     SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false);
-    SET_FLAG_FOR_TEST(flags::view_set_requested_frame_rate_mrr, true);
 
     auto layer = createLegacyAndFrontedEndLayer(1);
     setFrameRate(1, (45.6_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2860345..9020723 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -27,6 +27,7 @@
 #include "LayerHierarchyTest.h"
 #include "ui/GraphicTypes.h"
 
+#include <com_android_graphics_libgui_flags.h>
 #include <com_android_graphics_surfaceflinger_flags.h>
 
 #define UPDATE_AND_VERIFY(BUILDER, ...)                                    \
@@ -1761,4 +1762,162 @@
     UPDATE_AND_VERIFY(mSnapshotBuilder, {2});
     EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy());
 }
+TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
+    if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+        GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+    }
+    setCrop(1, Rect(0, 0, 20, 20));
+    setBuffer(1221,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(20 /* width */,
+                                                                        20 /* height */,
+                                                                        42ULL /* bufferId */,
+                                                                        HAL_PIXEL_FORMAT_RGBA_8888,
+                                                                        0 /*usage*/));
+    setEdgeExtensionEffect(12, LEFT);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(LEFT));
+    EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(LEFT));
+    EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(LEFT));
+
+    setEdgeExtensionEffect(12, RIGHT);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(RIGHT));
+    EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(RIGHT));
+    EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(RIGHT));
+
+    setEdgeExtensionEffect(12, TOP);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(TOP));
+    EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(TOP));
+    EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(TOP));
+
+    setEdgeExtensionEffect(12, BOTTOM);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(BOTTOM));
+    EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(BOTTOM));
+    EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(BOTTOM));
+}
+
+TEST_F(LayerSnapshotTest, leftEdgeExtensionIncreaseBoundSizeWithinCrop) {
+    // The left bound is extended when shifting to the right
+    if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+        GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+    }
+    setCrop(1, Rect(0, 0, 20, 20));
+    const int texSize = 10;
+    setBuffer(1221,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+                                                                        texSize /* height*/,
+                                                                        42ULL /* bufferId */,
+                                                                        HAL_PIXEL_FORMAT_RGBA_8888,
+                                                                        0 /*usage*/));
+    const float translation = 5.0;
+    setPosition(12, translation, 0);
+    setEdgeExtensionEffect(12, LEFT);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+    EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation);
+    EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0);
+}
+
+TEST_F(LayerSnapshotTest, rightEdgeExtensionIncreaseBoundSizeWithinCrop) {
+    // The right bound is extended when shifting to the left
+    if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+        GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+    }
+    const int crop = 20;
+    setCrop(1, Rect(0, 0, crop, crop));
+    const int texSize = 10;
+    setBuffer(1221,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+                                                                        texSize /* height*/,
+                                                                        42ULL /* bufferId */,
+                                                                        HAL_PIXEL_FORMAT_RGBA_8888,
+                                                                        0 /*usage*/));
+    const float translation = -5.0;
+    setPosition(12, translation, 0);
+    setEdgeExtensionEffect(12, RIGHT);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.left, 0);
+    EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+    EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop);
+}
+
+TEST_F(LayerSnapshotTest, topEdgeExtensionIncreaseBoundSizeWithinCrop) {
+    // The top bound is extended when shifting to the bottom
+    if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+        GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+    }
+    setCrop(1, Rect(0, 0, 20, 20));
+    const int texSize = 10;
+    setBuffer(1221,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+                                                                        texSize /* height*/,
+                                                                        42ULL /* bufferId */,
+                                                                        HAL_PIXEL_FORMAT_RGBA_8888,
+                                                                        0 /*usage*/));
+    const float translation = 5.0;
+    setPosition(12, 0, translation);
+    setEdgeExtensionEffect(12, TOP);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation);
+    EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation);
+    EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0.0);
+}
+
+TEST_F(LayerSnapshotTest, bottomEdgeExtensionIncreaseBoundSizeWithinCrop) {
+    // The bottom bound is extended when shifting to the top
+    if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+        GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+    }
+    const int crop = 20;
+    setCrop(1, Rect(0, 0, crop, crop));
+    const int texSize = 10;
+    setBuffer(1221,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+                                                                        texSize /* height*/,
+                                                                        42ULL /* bufferId */,
+                                                                        HAL_PIXEL_FORMAT_RGBA_8888,
+                                                                        0 /*usage*/));
+    const float translation = -5.0;
+    setPosition(12, 0, translation);
+    setEdgeExtensionEffect(12, BOTTOM);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.top, 0);
+    EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize - translation);
+    EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop);
+}
+
+TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) {
+    // The left bound is extended when shifting to the right
+    if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+        GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
+    }
+    const int crop = 20;
+    setCrop(1, Rect(0, 0, crop, crop));
+    const int texSize = 10;
+    setBuffer(1221,
+              std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */,
+                                                                        texSize /* height*/,
+                                                                        42ULL /* bufferId */,
+                                                                        HAL_PIXEL_FORMAT_RGBA_8888,
+                                                                        0 /*usage*/));
+    const float translation = 5.0;
+    setPosition(12, translation, translation);
+    setEdgeExtensionEffect(12, LEFT | RIGHT | TOP | BOTTOM);
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation);
+    EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop);
+    EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation);
+    EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0);
+    EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation);
+    EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop);
+    EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation);
+    EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0);
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 06c4e30..9efe73d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1837,6 +1837,43 @@
     }
 }
 
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_vrrHighHintTouch_primaryRangeIsSingleRate) {
+    if (GetParam() != Config::FrameRateOverride::Enabled) {
+        return;
+    }
+
+    SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+    auto selector = createSelector(kVrrMode_120, kModeId120);
+    selector.setActiveMode(kModeId120, 60_Hz);
+
+    // Change primary physical range to be single rate, which on VRR device should not affect
+    // fps scoring.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}));
+
+    std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+    layers[0].vote = LayerVoteType::ExplicitCategory;
+    layers[0].frameRateCategory = FrameRateCategory::HighHint;
+    layers[0].name = "ExplicitCategory HighHint";
+
+    auto actualRankedFrameRates = selector.getRankedFrameRates(layers);
+    // Expect late touch boost from HighHint.
+    EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+    EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+    EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+
+    layers[1].vote = LayerVoteType::ExplicitExactOrMultiple;
+    layers[1].desiredRefreshRate = 30_Hz;
+    layers[1].name = "ExplicitExactOrMultiple 30Hz";
+
+    actualRankedFrameRates = selector.getRankedFrameRates(layers);
+    // Expect late touch boost from HighHint.
+    EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+    EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+    EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+}
+
 TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) {
     auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60);
 
@@ -1955,7 +1992,7 @@
     // Gets touch boost
     EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
     EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
-    EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+    EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
 }
 
 TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_TouchBoost) {
@@ -2049,7 +2086,7 @@
     lr2.name = "Max";
     actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true});
     EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, actualRankedFrameRates.ranking.front().frameRateMode);
-    EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+    EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
 
     lr1.vote = LayerVoteType::ExplicitCategory;
     lr1.frameRateCategory = FrameRateCategory::Normal;
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 710b5cc..22d7b24 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -335,13 +335,6 @@
         return mFlinger->mLegacyLayers[layerId]->findOutputLayerForDisplay(display.get());
     }
 
-    static void setLayerSidebandStream(const sp<Layer>& layer,
-                                       const sp<NativeHandle>& sidebandStream) {
-        layer->mDrawingState.sidebandStream = sidebandStream;
-        layer->mSidebandStream = sidebandStream;
-        layer->editLayerSnapshot()->sidebandStream = sidebandStream;
-    }
-
     void setLayerCompositionType(const sp<Layer>& layer,
                                  aidl::android::hardware::graphics::composer3::Composition type) {
         auto outputLayer = findOutputLayerForDisplay(static_cast<uint32_t>(layer->sequence),
@@ -352,10 +345,6 @@
         (*state.hwc).hwcCompositionType = type;
     }
 
-    static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) {
-        layer->mDrawingParent = drawingParent;
-    }
-
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 7c678bd..918107d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -915,7 +915,8 @@
 
     vrrTracker.onFrameBegin(TimePoint::fromNs(7000),
                             {TimePoint::fromNs(6500), TimePoint::fromNs(6500)});
-    EXPECT_EQ(10500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
+    EXPECT_EQ(8500, vrrTracker.nextAnticipatedVSyncTimeFrom(8000, 7000));
+    EXPECT_EQ(9500, vrrTracker.nextAnticipatedVSyncTimeFrom(9000, 7000));
 }
 
 TEST_F(VSyncPredictorTest, adjustsVrrTimelineTwoClients) {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index fdb6f4d..45f86fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,15 +31,11 @@
 
     explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
 
-    MOCK_CONST_METHOD0(getType, const char*());
     MOCK_METHOD0(getFrameSelectionPriority, int32_t());
-    MOCK_CONST_METHOD0(isVisible, bool());
     MOCK_METHOD0(createClone, sp<Layer>());
     MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
     MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, scheduler::FrameRateCompatibility());
     MOCK_CONST_METHOD0(getOwnerUid, uid_t());
-    MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
-    MOCK_METHOD(bool, isFrontBuffered, (), (const, override));
 };
 
 } // namespace android::mock
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 4c4e341..879d2d0 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -27,9 +27,6 @@
     symbol_file: "libvulkan.map.txt",
     first_version: "24",
     unversioned_until: "current",
-    export_header_libs: [
-        "ndk_vulkan_headers",
-    ],
 }
 
 aconfig_declarations {