Merge "Add a new uwb ranging app-ops" into sc-dev
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 144dbd3..b0e8c7c 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -58,13 +58,13 @@
 // transport itself and should be moved to AIDL or in domain-specific libs.
 //
 // Currently, these are only on system android (not vendor, not host)
+// TODO(b/183654927) - move these into separate libraries
 libbinder_device_interface_sources = [
     "ActivityManager.cpp",
     "AppOpsManager.cpp",
     "IActivityManager.cpp",
     "IAppOpsCallback.cpp",
     "IAppOpsService.cpp",
-    "IBatteryStats.cpp",
     "IMediaResourceMonitor.cpp",
     "IPermissionController.cpp",
     "IProcessInfoService.cpp",
@@ -263,3 +263,23 @@
         },
     },
 }
+
+// libbinder historically contained additional interfaces that provided specific
+// functionality in the platform but have nothing to do with binder itself. These
+// are moved out of libbinder in order to avoid the overhead of their vtables.
+// If you are working on or own one of these interfaces, the responsible things
+// to would be:
+// - give them a new home
+// - convert them to AIDL instead of having manually written parceling code
+
+cc_library {
+    name: "libbatterystats_aidl",
+    srcs: [
+        "IBatteryStats.cpp",
+    ],
+    export_include_dirs: ["include_batterystats"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+}
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index d0085df..0de804c 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <binder/IBatteryStats.h>
+#include <batterystats/IBatteryStats.h>
 
 #include <utils/Log.h>
 #include <binder/Parcel.h>
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index 83a1618..dab3246 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -20,6 +20,7 @@
 
 #include <binder/Parcel.h>
 #include <binder/Stability.h>
+#include <utils/String8.h>
 
 #include "RpcState.h"
 #include "RpcWireFormat.h"
@@ -29,14 +30,20 @@
 #include <sys/un.h>
 #include <unistd.h>
 
-#if defined(__GLIBC__)
+#ifdef __GLIBC__
 extern "C" pid_t gettid();
 #endif
 
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif
+
 namespace android {
 
 using base::unique_fd;
 
+RpcConnection::SocketAddress::~SocketAddress() {}
+
 RpcConnection::RpcConnection() {
     LOG_RPC_DETAIL("RpcConnection created %p", this);
 
@@ -50,65 +57,68 @@
     return new RpcConnection;
 }
 
+class UnixSocketAddress : public RpcConnection::SocketAddress {
+public:
+    explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
+        unsigned int pathLen = strlen(path) + 1;
+        LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "%u %s", pathLen, path);
+        memcpy(mAddr.sun_path, path, pathLen);
+    }
+    virtual ~UnixSocketAddress() {}
+    std::string toString() const override {
+        return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
+                               mAddr.sun_path)
+                .c_str();
+    }
+    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+    size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+    sockaddr_un mAddr;
+};
+
 bool RpcConnection::setupUnixDomainServer(const char* path) {
-    LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Only supports one server now");
-
-    unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
-    if (serverFd == -1) {
-        ALOGE("Could not create socket at %s: %s", path, strerror(errno));
-        return false;
-    }
-
-    struct sockaddr_un addr = {
-            .sun_family = AF_UNIX,
-    };
-
-    unsigned int pathLen = strlen(path) + 1;
-    LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen);
-    memcpy(addr.sun_path, path, pathLen);
-
-    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) {
-        ALOGE("Could not bind socket at %s: %s", path, strerror(errno));
-        return false;
-    }
-
-    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
-        ALOGE("Could not listen socket at %s: %s", path, strerror(errno));
-        return false;
-    }
-
-    mServer = std::move(serverFd);
-    return true;
+    return addServer(UnixSocketAddress(path));
 }
 
 bool RpcConnection::addUnixDomainClient(const char* path) {
-    LOG_RPC_DETAIL("Connecting on path: %s", path);
-
-    unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
-    if (serverFd == -1) {
-        ALOGE("Could not create socket at %s: %s", path, strerror(errno));
-        return false;
-    }
-
-    struct sockaddr_un addr = {
-            .sun_family = AF_UNIX,
-    };
-
-    unsigned int pathLen = strlen(path) + 1;
-    LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen);
-    memcpy(addr.sun_path, path, pathLen);
-
-    if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) {
-        ALOGE("Could not connect socket at %s: %s", path, strerror(errno));
-        return false;
-    }
-
-    LOG_RPC_DETAIL("Unix domain client with fd %d", serverFd.get());
-
-    addClient(std::move(serverFd));
-    return true;
+    return addClient(UnixSocketAddress(path));
 }
 
+#ifdef __BIONIC__
+
+class VsockSocketAddress : public RpcConnection::SocketAddress {
+public:
+    VsockSocketAddress(unsigned int cid, unsigned int port)
+          : mAddr({
+                    .svm_family = AF_VSOCK,
+                    .svm_port = port,
+                    .svm_cid = cid,
+            }) {}
+    virtual ~VsockSocketAddress() {}
+    std::string toString() const override {
+        return String8::format("cid %du port %du", mAddr.svm_cid, mAddr.svm_port).c_str();
+    }
+    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+    size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+    sockaddr_vm mAddr;
+};
+
+bool RpcConnection::setupVsockServer(unsigned int port) {
+    // realizing value w/ this type at compile time to avoid ubsan abort
+    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
+
+    return addServer(VsockSocketAddress(kAnyCid, port));
+}
+
+bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
+    return addClient(VsockSocketAddress(cid, port));
+}
+
+#endif // __BIONIC__
+
 sp<IBinder> RpcConnection::getRootObject() {
     ExclusiveSocket socket(this, SocketUse::CLIENT);
     return state()->getRootObject(socket.fd(), this);
@@ -130,11 +140,8 @@
 void RpcConnection::join() {
     // establish a connection
     {
-        struct sockaddr_un clientSa;
-        socklen_t clientSaLen = sizeof(clientSa);
-
-        unique_fd clientFd(TEMP_FAILURE_RETRY(
-                accept4(mServer.get(), (struct sockaddr*)&clientSa, &clientSaLen, SOCK_CLOEXEC)));
+        unique_fd clientFd(
+                TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
         if (clientFd < 0) {
             // If this log becomes confusing, should save more state from setupUnixDomainServer
             // in order to output here.
@@ -144,7 +151,7 @@
 
         LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
 
-        addServer(std::move(clientFd));
+        assignServerToThisThread(std::move(clientFd));
     }
 
     // We may not use the connection we just established (two threads might
@@ -170,14 +177,57 @@
     return mForServer;
 }
 
-void RpcConnection::addClient(base::unique_fd&& fd) {
-    std::lock_guard<std::mutex> _l(mSocketMutex);
-    sp<ConnectionSocket> connection = new ConnectionSocket();
-    connection->fd = std::move(fd);
-    mClients.push_back(connection);
+bool RpcConnection::addServer(const SocketAddress& addr) {
+    LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");
+
+    unique_fd serverFd(
+            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    if (serverFd == -1) {
+        ALOGE("Could not create socket: %s", strerror(errno));
+        return false;
+    }
+
+    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
+        int savedErrno = errno;
+        ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        return false;
+    }
+
+    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+        int savedErrno = errno;
+        ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        return false;
+    }
+
+    mServer = std::move(serverFd);
+    return true;
 }
 
-void RpcConnection::addServer(base::unique_fd&& fd) {
+bool RpcConnection::addClient(const SocketAddress& addr) {
+    unique_fd serverFd(
+            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    if (serverFd == -1) {
+        int savedErrno = errno;
+        ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        return false;
+    }
+
+    if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+        int savedErrno = errno;
+        ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        return false;
+    }
+
+    LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
+
+    std::lock_guard<std::mutex> _l(mSocketMutex);
+    sp<ConnectionSocket> connection = new ConnectionSocket();
+    connection->fd = std::move(serverFd);
+    mClients.push_back(connection);
+    return true;
+}
+
+void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) {
     std::lock_guard<std::mutex> _l(mSocketMutex);
     sp<ConnectionSocket> connection = new ConnectionSocket();
     connection->fd = std::move(fd);
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index 65c5232..a300575 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -61,6 +61,18 @@
      */
     [[nodiscard]] bool addUnixDomainClient(const char* path);
 
+#ifdef __BIONIC__
+    /**
+     * Creates an RPC server at the current port.
+     */
+    [[nodiscard]] bool setupVsockServer(unsigned int port);
+
+    /**
+     * Connects to an RPC server at the CVD & port.
+     */
+    [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
+#endif // __BIONIC__
+
     /**
      * Query the other side of the connection for the root object hosted by that
      * process's RpcServer (if one exists)
@@ -85,11 +97,20 @@
     // internal only
     const std::unique_ptr<RpcState>& state() { return mState; }
 
+    class SocketAddress {
+    public:
+        virtual ~SocketAddress();
+        virtual std::string toString() const = 0;
+        virtual const sockaddr* addr() const = 0;
+        virtual size_t addrSize() const = 0;
+    };
+
 private:
     RpcConnection();
 
-    void addServer(base::unique_fd&& fd);
-    void addClient(base::unique_fd&& fd);
+    bool addServer(const SocketAddress& address);
+    bool addClient(const SocketAddress& address);
+    void assignServerToThisThread(base::unique_fd&& fd);
 
     struct ConnectionSocket : public RefBase {
         base::unique_fd fd;
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include_batterystats/batterystats/IBatteryStats.h
similarity index 100%
rename from libs/binder/include/binder/IBatteryStats.h
rename to libs/binder/include_batterystats/batterystats/IBatteryStats.h
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index a44cddf..77fa91f 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -106,6 +106,12 @@
 
 cc_test {
     name: "binderRpcTest",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
     defaults: ["binder_test_defaults"],
 
     srcs: [
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 6fa5333..936ee5e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,14 +14,6 @@
  * limitations under the License.
  */
 
-#include <sys/prctl.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <cstdlib>
-#include <iostream>
-#include <thread>
-
 #include <BnBinderRpcSession.h>
 #include <BnBinderRpcTest.h>
 #include <android-base/logging.h>
@@ -33,6 +25,18 @@
 #include <binder/RpcServer.h>
 #include <gtest/gtest.h>
 
+#include <chrono>
+#include <cstdlib>
+#include <iostream>
+#include <thread>
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif //__BIONIC__
+
+#include <sys/prctl.h>
+#include <unistd.h>
+
 #include "../RpcState.h" // for debugging
 
 namespace android {
@@ -185,8 +189,13 @@
 
 static std::string allocateSocketAddress() {
     static size_t id = 0;
+    static bool gUseTmp = access("/tmp/", F_OK) != -1;
 
-    return "/dev/binderRpcTest_" + std::to_string(id++);
+    if (gUseTmp) {
+        return "/tmp/binderRpcTest_" + std::to_string(id++);
+    } else {
+        return "/dev/binderRpcTest_" + std::to_string(id++);
+    }
 };
 
 struct ProcessConnection {
@@ -214,58 +223,6 @@
     }
 };
 
-// This creates a new process serving an interface on a certain number of
-// threads.
-ProcessConnection createRpcTestSocketServerProcess(
-        size_t numThreads,
-        const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
-    CHECK_GT(numThreads, 0);
-
-    std::string addr = allocateSocketAddress();
-    unlink(addr.c_str());
-
-    auto ret = ProcessConnection{
-            .host = Process([&] {
-                sp<RpcServer> server = RpcServer::make();
-
-                server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
-                // server supporting one client on one socket
-                sp<RpcConnection> connection = server->addClientConnection();
-                CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
-
-                configure(server, connection);
-
-                // accept 'numThreads' connections
-                std::vector<std::thread> pool;
-                for (size_t i = 0; i + 1 < numThreads; i++) {
-                    pool.push_back(std::thread([=] { connection->join(); }));
-                }
-                connection->join();
-                for (auto& t : pool) t.join();
-            }),
-            .connection = RpcConnection::make(),
-    };
-
-    // wait up to 1s for sockets to be created
-    constexpr useconds_t kMaxWaitUs = 1000000;
-    constexpr useconds_t kWaitDivision = 100;
-    for (size_t i = 0; i < kWaitDivision && 0 != access(addr.c_str(), F_OK); i++) {
-        usleep(kMaxWaitUs / kWaitDivision);
-    }
-
-    // create remainder of connections
-    for (size_t i = 0; i < numThreads; i++) {
-        // Connection refused sometimes after file created but before listening.
-        CHECK(ret.connection->addUnixDomainClient(addr.c_str()) ||
-              (usleep(10000), ret.connection->addUnixDomainClient(addr.c_str())))
-                << i;
-    }
-
-    ret.rootBinder = ret.connection->getRootObject();
-    return ret;
-}
-
 // Process connection where the process hosts IBinderRpcTest, the server used
 // for most testing here
 struct BinderRpcTestProcessConnection {
@@ -290,26 +247,122 @@
     }
 };
 
-BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
-    BinderRpcTestProcessConnection ret{
-            .proc = createRpcTestSocketServerProcess(numThreads,
-                                                     [&](const sp<RpcServer>& server,
-                                                         const sp<RpcConnection>& connection) {
-                                                         sp<MyBinderRpcTest> service =
-                                                                 new MyBinderRpcTest;
-                                                         server->setRootObject(service);
-                                                         service->connection =
-                                                                 connection; // for testing only
-                                                     }),
-    };
-
-    ret.rootBinder = ret.proc.rootBinder;
-    ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
-
-    return ret;
+enum class SocketType {
+    UNIX,
+#ifdef __BIONIC__
+    VSOCK,
+#endif // __BIONIC__
+};
+static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
+    switch (info.param) {
+        case SocketType::UNIX:
+            return "unix_domain_socket";
+#ifdef __BIONIC__
+        case SocketType::VSOCK:
+            return "vm_socket";
+#endif // __BIONIC__
+        default:
+            LOG_ALWAYS_FATAL("Unknown socket type");
+            return "";
+    }
 }
+class BinderRpc : public ::testing::TestWithParam<SocketType> {
+public:
+    // This creates a new process serving an interface on a certain number of
+    // threads.
+    ProcessConnection createRpcTestSocketServerProcess(
+            size_t numThreads,
+            const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
+        CHECK_GT(numThreads, 0);
 
-TEST(BinderRpc, RootObjectIsNull) {
+        SocketType socketType = GetParam();
+
+        std::string addr = allocateSocketAddress();
+        unlink(addr.c_str());
+        static unsigned int port = 3456;
+        port++;
+
+        auto ret = ProcessConnection{
+                .host = Process([&] {
+                    sp<RpcServer> server = RpcServer::make();
+
+                    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+                    // server supporting one client on one socket
+                    sp<RpcConnection> connection = server->addClientConnection();
+
+                    switch (socketType) {
+                        case SocketType::UNIX:
+                            CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
+                            break;
+#ifdef __BIONIC__
+                        case SocketType::VSOCK:
+                            CHECK(connection->setupVsockServer(port));
+                            break;
+#endif // __BIONIC__
+                        default:
+                            LOG_ALWAYS_FATAL("Unknown socket type");
+                    }
+
+                    configure(server, connection);
+
+                    // accept 'numThreads' connections
+                    std::vector<std::thread> pool;
+                    for (size_t i = 0; i + 1 < numThreads; i++) {
+                        pool.push_back(std::thread([=] { connection->join(); }));
+                    }
+                    connection->join();
+                    for (auto& t : pool) t.join();
+                }),
+                .connection = RpcConnection::make(),
+        };
+
+        // create remainder of connections
+        for (size_t i = 0; i < numThreads; i++) {
+            for (size_t tries = 0; tries < 5; tries++) {
+                usleep(10000);
+                switch (socketType) {
+                    case SocketType::UNIX:
+                        if (ret.connection->addUnixDomainClient(addr.c_str())) goto success;
+                        break;
+#ifdef __BIONIC__
+                    case SocketType::VSOCK:
+                        if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success;
+                        break;
+#endif // __BIONIC__
+                    default:
+                        LOG_ALWAYS_FATAL("Unknown socket type");
+                }
+            }
+            LOG_ALWAYS_FATAL("Could not connect");
+        success:;
+        }
+
+        ret.rootBinder = ret.connection->getRootObject();
+        return ret;
+    }
+
+    BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
+        BinderRpcTestProcessConnection ret{
+                .proc = createRpcTestSocketServerProcess(numThreads,
+                                                         [&](const sp<RpcServer>& server,
+                                                             const sp<RpcConnection>& connection) {
+                                                             sp<MyBinderRpcTest> service =
+                                                                     new MyBinderRpcTest;
+                                                             server->setRootObject(service);
+                                                             service->connection =
+                                                                     connection; // for testing only
+                                                         }),
+        };
+
+        ret.rootBinder = ret.proc.rootBinder;
+        ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+        return ret;
+    }
+};
+
+TEST_P(BinderRpc, RootObjectIsNull) {
     auto proc = createRpcTestSocketServerProcess(1,
                                                  [](const sp<RpcServer>& server,
                                                     const sp<RpcConnection>&) {
@@ -324,20 +377,20 @@
     EXPECT_EQ(nullptr, proc.connection->getRootObject());
 }
 
-TEST(BinderRpc, Ping) {
+TEST_P(BinderRpc, Ping) {
     auto proc = createRpcTestSocketServerProcess(1);
     ASSERT_NE(proc.rootBinder, nullptr);
     EXPECT_EQ(OK, proc.rootBinder->pingBinder());
 }
 
-TEST(BinderRpc, TransactionsMustBeMarkedRpc) {
+TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
     auto proc = createRpcTestSocketServerProcess(1);
     Parcel data;
     Parcel reply;
     EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
 }
 
-TEST(BinderRpc, UnknownTransaction) {
+TEST_P(BinderRpc, UnknownTransaction) {
     auto proc = createRpcTestSocketServerProcess(1);
     Parcel data;
     data.markForBinder(proc.rootBinder);
@@ -345,19 +398,19 @@
     EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
 }
 
-TEST(BinderRpc, SendSomethingOneway) {
+TEST_P(BinderRpc, SendSomethingOneway) {
     auto proc = createRpcTestSocketServerProcess(1);
     EXPECT_OK(proc.rootIface->sendString("asdf"));
 }
 
-TEST(BinderRpc, SendAndGetResultBack) {
+TEST_P(BinderRpc, SendAndGetResultBack) {
     auto proc = createRpcTestSocketServerProcess(1);
     std::string doubled;
     EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
     EXPECT_EQ("cool cool ", doubled);
 }
 
-TEST(BinderRpc, SendAndGetResultBackBig) {
+TEST_P(BinderRpc, SendAndGetResultBackBig) {
     auto proc = createRpcTestSocketServerProcess(1);
     std::string single = std::string(1024, 'a');
     std::string doubled;
@@ -365,7 +418,7 @@
     EXPECT_EQ(single + single, doubled);
 }
 
-TEST(BinderRpc, CallMeBack) {
+TEST_P(BinderRpc, CallMeBack) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     int32_t pingResult;
@@ -375,7 +428,7 @@
     EXPECT_EQ(0, MyBinderRpcSession::gNum);
 }
 
-TEST(BinderRpc, RepeatBinder) {
+TEST_P(BinderRpc, RepeatBinder) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinder> inBinder = new MyBinderRpcSession("foo");
@@ -397,7 +450,7 @@
     EXPECT_EQ(0, MyBinderRpcSession::gNum);
 }
 
-TEST(BinderRpc, RepeatTheirBinder) {
+TEST_P(BinderRpc, RepeatTheirBinder) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinderRpcSession> session;
@@ -421,7 +474,7 @@
     EXPECT_EQ(nullptr, weak.promote());
 }
 
-TEST(BinderRpc, RepeatBinderNull) {
+TEST_P(BinderRpc, RepeatBinderNull) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinder> outBinder;
@@ -429,7 +482,7 @@
     EXPECT_EQ(nullptr, outBinder);
 }
 
-TEST(BinderRpc, HoldBinder) {
+TEST_P(BinderRpc, HoldBinder) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     IBinder* ptr = nullptr;
@@ -455,7 +508,7 @@
 // These are behavioral differences form regular binder, where certain usecases
 // aren't supported.
 
-TEST(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) {
+TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) {
     auto proc1 = createRpcTestSocketServerProcess(1);
     auto proc2 = createRpcTestSocketServerProcess(1);
 
@@ -464,7 +517,7 @@
               proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
 }
 
-TEST(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
@@ -473,7 +526,7 @@
               proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
 }
 
-TEST(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     // for historical reasons, IServiceManager interface only returns the
@@ -484,7 +537,7 @@
 
 // END TESTS FOR LIMITATIONS OF SOCKET BINDER
 
-TEST(BinderRpc, RepeatRootObject) {
+TEST_P(BinderRpc, RepeatRootObject) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinder> outBinder;
@@ -492,7 +545,7 @@
     EXPECT_EQ(proc.rootBinder, outBinder);
 }
 
-TEST(BinderRpc, NestedTransactions) {
+TEST_P(BinderRpc, NestedTransactions) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     auto nastyNester = sp<MyBinderRpcTest>::make();
@@ -503,7 +556,7 @@
     EXPECT_EQ(nullptr, weak.promote());
 }
 
-TEST(BinderRpc, SameBinderEquality) {
+TEST_P(BinderRpc, SameBinderEquality) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinder> a;
@@ -515,7 +568,7 @@
     EXPECT_EQ(a, b);
 }
 
-TEST(BinderRpc, SameBinderEqualityWeak) {
+TEST_P(BinderRpc, SameBinderEqualityWeak) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinder> a;
@@ -547,7 +600,7 @@
         EXPECT_EQ(expected, session);                     \
     } while (false)
 
-TEST(BinderRpc, SingleSession) {
+TEST_P(BinderRpc, SingleSession) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     sp<IBinderRpcSession> session;
@@ -561,7 +614,7 @@
     expectSessions(0, proc.rootIface);
 }
 
-TEST(BinderRpc, ManySessions) {
+TEST_P(BinderRpc, ManySessions) {
     auto proc = createRpcTestSocketServerProcess(1);
 
     std::vector<sp<IBinderRpcSession>> sessions;
@@ -595,7 +648,7 @@
     return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
 }
 
-TEST(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
     constexpr size_t kNumThreads = 10;
 
     auto proc = createRpcTestSocketServerProcess(kNumThreads);
@@ -627,7 +680,7 @@
     for (auto& t : ts) t.join();
 }
 
-TEST(BinderRpc, ThreadPoolOverSaturated) {
+TEST_P(BinderRpc, ThreadPoolOverSaturated) {
     constexpr size_t kNumThreads = 10;
     constexpr size_t kNumCalls = kNumThreads + 3;
     constexpr size_t kSleepMs = 500;
@@ -651,7 +704,7 @@
     EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
 }
 
-TEST(BinderRpc, ThreadingStressTest) {
+TEST_P(BinderRpc, ThreadingStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 100;
@@ -672,7 +725,7 @@
     for (auto& t : threads) t.join();
 }
 
-TEST(BinderRpc, OnewayCallDoesNotWait) {
+TEST_P(BinderRpc, OnewayCallDoesNotWait) {
     constexpr size_t kReallyLongTimeMs = 100;
     constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
 
@@ -687,7 +740,7 @@
     EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
 }
 
-TEST(BinderRpc, OnewayCallQueueing) {
+TEST_P(BinderRpc, OnewayCallQueueing) {
     constexpr size_t kNumSleeps = 10;
     constexpr size_t kNumExtraServerThreads = 4;
     constexpr size_t kSleepMs = 50;
@@ -711,7 +764,7 @@
     EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
 }
 
-TEST(BinderRpc, Die) {
+TEST_P(BinderRpc, Die) {
     // TODO(b/183141167): handle this in library
     signal(SIGPIPE, SIG_IGN);
 
@@ -743,7 +796,7 @@
     return ret;
 }
 
-TEST(BinderRpc, Fds) {
+TEST_P(BinderRpc, Fds) {
     ssize_t beforeFds = countFds();
     ASSERT_GE(beforeFds, 0);
     {
@@ -753,10 +806,19 @@
     ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
 }
 
-extern "C" int main(int argc, char** argv) {
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+                        ::testing::Values(SocketType::UNIX
+#ifdef __BIONIC__
+                                          ,
+                                          SocketType::VSOCK
+#endif // __BIONIC__
+                                          ),
+                        PrintSocketType);
+
+} // namespace android
+
+int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
     return RUN_ALL_TESTS();
 }
-
-} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ae4f8fe..2a9a97e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -564,6 +564,10 @@
     }
 }
 
+bool layer_state_t::hasBufferChanges() const {
+    return (what & layer_state_t::eBufferChanged) || (what & layer_state_t::eCachedBufferChanged);
+}
+
 status_t layer_state_t::matrix22_t::write(Parcel& output) const {
     SAFE_PARCEL(output.writeFloat, dsdx);
     SAFE_PARCEL(output.writeFloat, dtdx);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 4bd12ce..6c265c8 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -127,6 +127,7 @@
     void merge(const layer_state_t& other);
     status_t write(Parcel& output) const;
     status_t read(const Parcel& input);
+    bool hasBufferChanges() const;
 
     struct matrix22_t {
         float dsdx{0};
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 06a1722..cd7a86b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -73,6 +73,7 @@
     bool cleanupPostRender(CleanupMode mode) override;
     int getContextPriority() override;
     bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
+    void onPrimaryDisplaySizeChanged(ui::Size size) override {}
 
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     // Creates an output image for rendering to
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 035c46f..a69d1f0 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -153,6 +153,10 @@
     virtual bool supportsProtectedContent() const = 0;
     virtual bool useProtectedContext(bool useProtectedContext) = 0;
 
+    // Notify RenderEngine of changes to the dimensions of the primary display
+    // so that it can configure its internal caches accordingly.
+    virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0;
+
     // Renders layers for a particular display via GPU composition. This method
     // should be called for every display that needs to be rendered via the GPU.
     // @param display The display-wide settings that should be applied prior to
@@ -289,8 +293,7 @@
     bool precacheToneMapperShaderOnly = false;
     bool supportsBackgroundBlur = false;
     RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
-    RenderEngine::RenderEngineType renderEngineType =
-            RenderEngine::RenderEngineType::SKIA_GL_THREADED;
+    RenderEngine::RenderEngineType renderEngineType = RenderEngine::RenderEngineType::GLES;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 5f75b81..228553d 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -55,6 +55,7 @@
     MOCK_METHOD0(cleanFramebufferCache, void());
     MOCK_METHOD0(getContextPriority, int());
     MOCK_METHOD0(supportsBackgroundBlur, bool());
+    MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size));
 };
 
 } // namespace mock
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c7001b9..0798562 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -294,12 +294,13 @@
         mPlaceholderSurface(placeholder),
         mProtectedEGLContext(protectedContext),
         mProtectedPlaceholderSurface(protectedPlaceholder),
+        mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)),
         mUseColorManagement(args.useColorManagement) {
     sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
     LOG_ALWAYS_FATAL_IF(!glInterface.get());
 
     GrContextOptions options;
-    options.fPreferExternalImagesOverES3 = true;
+    options.fDisableDriverCorrectnessWorkarounds = true;
     options.fDisableDistanceFieldPaths = true;
     options.fPersistentCache = &mSkSLCacheMonitor;
     mGrContext = GrDirectContext::MakeGL(glInterface, options);
@@ -1186,6 +1187,27 @@
     return value;
 }
 
+void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) {
+    // This cache multiplier was selected based on review of cache sizes relative
+    // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
+    // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
+    // conservative default based on that analysis.
+    const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
+    const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
+
+    // start by resizing the current context
+    auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
+    grContext->setResourceCacheLimit(maxResourceBytes);
+
+    // if it is possible to switch contexts then we will resize the other context
+    if (useProtectedContext(!mInProtectedContext)) {
+        grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
+        grContext->setResourceCacheLimit(maxResourceBytes);
+        // reset back to the initial context that was active when this method was called
+        useProtectedContext(!mInProtectedContext);
+    }
+}
+
 void SkiaGLRenderEngine::dump(std::string& result) {
     const gl::GLExtensions& extensions = gl::GLExtensions::getInstance();
 
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 7605df9..25557f1 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -65,6 +65,7 @@
     bool useProtectedContext(bool useProtectedContext) override;
     bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
     void assertShadersCompiled(int numShaders) override;
+    void onPrimaryDisplaySizeChanged(ui::Size size) override;
 
 protected:
     void dump(std::string& result) override;
@@ -109,6 +110,7 @@
     EGLSurface mProtectedPlaceholderSurface;
     BlurFilter* mBlurFilter = nullptr;
 
+    const PixelFormat mDefaultPixelFormat;
     const bool mUseColorManagement;
 
     // Cache of GL textures that we'll store per GraphicBuffer ID
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 6a91c7c..783e37f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -332,6 +332,21 @@
     return resultFuture.get();
 }
 
+void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) {
+    std::promise<void> resultPromise;
+    std::future<void> resultFuture = resultPromise.get_future();
+    {
+        std::lock_guard lock(mThreadMutex);
+        mFunctionCalls.push([&resultPromise, size](renderengine::RenderEngine& instance) {
+            ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged");
+            instance.onPrimaryDisplaySizeChanged(size);
+            resultPromise.set_value();
+        });
+    }
+    mCondition.notify_one();
+    resultFuture.wait();
+}
+
 } // namespace threaded
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 7694328..117257a 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -66,6 +66,7 @@
     void cleanFramebufferCache() override;
     int getContextPriority() override;
     bool supportsBackgroundBlur() override;
+    void onPrimaryDisplaySizeChanged(ui::Size size) override;
 
 private:
     void threadMain(CreateInstanceFactory factory);
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index ca9ff7c..c769e97 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -7,9 +7,6 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
-subdirs = [
-    "hidl"
-]
 cc_library_shared {
     name: "libsensorservice",
 
@@ -52,6 +49,7 @@
         "libhardware_legacy",
         "libutils",
         "liblog",
+        "libbatterystats_aidl",
         "libbinder",
         "libsensor",
         "libsensorprivacy",
diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h
index 43a750c..09eb2c1 100644
--- a/services/sensorservice/BatteryService.h
+++ b/services/sensorservice/BatteryService.h
@@ -17,7 +17,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <binder/IBatteryStats.h>
+#include <batterystats/IBatteryStats.h>
 #include <utils/Singleton.h>
 
 namespace android {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index a3e84e2..6c02759 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -16,10 +16,7 @@
 
 #pragma once
 
-#include <cstdint>
-#include <optional>
-#include <string>
-
+#include <compositionengine/ProjectionSpace.h>
 #include <compositionengine/impl/HwcBufferCache.h>
 #include <renderengine/Mesh.h>
 #include <ui/FloatRect.h>
@@ -27,6 +24,10 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
+#include <cstdint>
+#include <optional>
+#include <string>
+
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
@@ -90,6 +91,7 @@
         sp<Fence> acquireFence = nullptr;
         Rect displayFrame = {};
         ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+        ProjectionSpace displaySpace;
     } overrideInfo;
 
     /*
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index a56f28a..056408e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <compositionengine/Output.h>
+#include <compositionengine/ProjectionSpace.h>
 #include <compositionengine/impl/planner/LayerState.h>
 #include <renderengine/RenderEngine.h>
 
@@ -38,7 +40,9 @@
         const LayerState* getState() const { return mState; }
         const std::string& getName() const { return mState->getName(); }
         Rect getDisplayFrame() const { return mState->getDisplayFrame(); }
-        const sp<GraphicBuffer>& getBuffer() const { return mState->getBuffer(); }
+        const sp<GraphicBuffer>& getBuffer() const {
+            return mState->getOutputLayer()->getLayerFE().getCompositionState()->buffer;
+        }
         int64_t getFramesSinceBufferUpdate() const { return mState->getFramesSinceBufferUpdate(); }
         NonBufferHash getHash() const { return mHash; }
         std::chrono::steady_clock::time_point getLastUpdate() const { return mLastUpdate; }
@@ -62,6 +66,7 @@
     size_t getAge() const { return mAge; }
     const sp<GraphicBuffer>& getBuffer() const { return mTexture.getBuffer(); }
     const sp<Fence>& getDrawFence() const { return mDrawFence; }
+    const ProjectionSpace& getOutputSpace() const { return mOutputSpace; }
     ui::Dataspace getOutputDataspace() const { return mOutputDataspace; }
 
     NonBufferHash getNonBufferHash() const;
@@ -92,8 +97,8 @@
     }
     void incrementAge() { ++mAge; }
 
-    // Renders the cached set with the supplied output dataspace.
-    void render(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
+    // Renders the cached set with the supplied output composition state.
+    void render(renderengine::RenderEngine& re, const OutputCompositionState& outputState);
 
     void dump(std::string& result) const;
 
@@ -132,7 +137,9 @@
 
     Texture mTexture;
     sp<Fence> mDrawFence;
+    ProjectionSpace mOutputSpace;
     ui::Dataspace mOutputDataspace;
+    ui::Transform::RotationFlags mOrientation = ui::Transform::ROT_0;
 
     static const bool sDebugHighlighLayers;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 2bd3249..313a180 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <compositionengine/Output.h>
 #include <compositionengine/impl/planner/CachedSet.h>
 #include <compositionengine/impl/planner/LayerState.h>
 
@@ -42,8 +43,9 @@
     NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash,
                                 std::chrono::steady_clock::time_point now);
 
-    // Renders the newest cached sets with the supplied output dataspace
-    void renderCachedSets(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
+    // Renders the newest cached sets with the supplied output composition state
+    void renderCachedSets(renderengine::RenderEngine& re,
+                          const OutputCompositionState& outputState);
 
     void dump(std::string& result) const;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index a3beadc..d005ca3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -32,6 +32,14 @@
 struct hash<android::sp<T>> {
     size_t operator()(const android::sp<T>& p) { return std::hash<void*>()(p.get()); }
 };
+
+template <typename T>
+struct hash<android::wp<T>> {
+    size_t operator()(const android::wp<T>& p) {
+        android::sp<T> promoted = p.promote();
+        return std::hash<void*>()(promoted ? promoted.get() : nullptr);
+    }
+};
 } // namespace std
 
 namespace android::compositionengine::impl::planner {
@@ -70,7 +78,7 @@
 
     virtual Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) = 0;
 
-    virtual size_t getHash(Flags<LayerStateField> skipFields) const = 0;
+    virtual size_t getHash() const = 0;
 
     virtual LayerStateField getField() const = 0;
 
@@ -113,6 +121,10 @@
     // Returns this member's field flag if it was changed
     Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) override {
         T newValue = mReader(layer);
+        return update(newValue);
+    }
+
+    Flags<LayerStateField> update(const T& newValue) {
         if (!mEquals(mValue, newValue)) {
             mValue = newValue;
             mHash = {};
@@ -124,10 +136,7 @@
     LayerStateField getField() const override { return FIELD; }
     const T& get() const { return mValue; }
 
-    size_t getHash(Flags<LayerStateField> skipFields) const override {
-        if (skipFields.test(FIELD)) {
-            return 0;
-        }
+    size_t getHash() const override {
         if (!mHash) {
             mHash = std::hash<T>{}(mValue);
         }
@@ -175,13 +184,13 @@
     Flags<LayerStateField> update(compositionengine::OutputLayer*);
 
     // Computes a hash for this LayerState.
-    // The hash is only computed from NonUniqueFields.
-    size_t getHash(Flags<LayerStateField> skipFields) const;
+    // The hash is only computed from NonUniqueFields, and excludes GraphicBuffers since they are
+    // not guaranteed to live longer than the LayerState object.
+    size_t getHash() const;
 
     // Returns the bit-set of differing fields between this LayerState and another LayerState.
-    // This bit-set is based on NonUniqueFields only
-    Flags<LayerStateField> getDifferingFields(const LayerState& other,
-                                              Flags<LayerStateField> skipFields) const;
+    // This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers.
+    Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
 
     compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; }
     int32_t getId() const { return mId.get(); }
@@ -190,7 +199,6 @@
     hardware::graphics::composer::hal::Composition getCompositionType() const {
         return mCompositionType.get();
     }
-    const sp<GraphicBuffer>& getBuffer() const { return mBuffer.get(); }
 
     void incrementFramesSinceBufferUpdate() { ++mFramesSinceBufferUpdate; }
     void resetFramesSinceBufferUpdate() { mFramesSinceBufferUpdate = 0; }
@@ -311,10 +319,14 @@
                                 return std::vector<std::string>{base::StringPrintf("%p", p)};
                             }};
 
-    OutputLayerState<sp<GraphicBuffer>, LayerStateField::Buffer>
+    OutputLayerState<wp<GraphicBuffer>, LayerStateField::Buffer>
             mBuffer{[](auto layer) { return layer->getLayerFE().getCompositionState()->buffer; },
-                    [](const sp<GraphicBuffer>& buffer) {
-                        return std::vector<std::string>{base::StringPrintf("%p", buffer.get())};
+                    [](const wp<GraphicBuffer>& buffer) {
+                        sp<GraphicBuffer> promotedBuffer = buffer.promote();
+                        return std::vector<std::string>{
+                                base::StringPrintf("%p",
+                                                   promotedBuffer ? promotedBuffer.get()
+                                                                  : nullptr)};
                     }};
 
     int64_t mFramesSinceBufferUpdate = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index 89de34d..e6d2b63 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -59,7 +59,8 @@
             compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers);
 
     // The planner will call to the Flattener to render any pending cached set
-    void renderCachedSets(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
+    void renderCachedSets(renderengine::RenderEngine& re,
+                          const OutputCompositionState& outputState);
 
     void dump(const Vector<String16>& args, std::string&);
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index ded2dcc..aed3be9 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1252,7 +1252,7 @@
 
 void Output::renderCachedSets() {
     if (mPlanner) {
-        mPlanner->renderCachedSets(getCompositionEngine().getRenderEngine(), getState().dataspace);
+        mPlanner->renderCachedSets(getCompositionEngine().getRenderEngine(), getState());
     }
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index b364649..4832793 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -354,6 +354,7 @@
 
     Rect displayFrame = outputDependentState.displayFrame;
     FloatRect sourceCrop = outputDependentState.sourceCrop;
+
     if (outputDependentState.overrideInfo.buffer != nullptr) { // adyabr
         displayFrame = outputDependentState.overrideInfo.displayFrame;
         sourceCrop = displayFrame.toFloatRect();
@@ -380,8 +381,9 @@
               outputDependentState.z, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    // Solid-color layers should always use an identity transform.
-    const auto bufferTransform = requestedCompositionType != hal::Composition::SOLID_COLOR
+    // Solid-color layers and overridden buffers should always use an identity transform.
+    const auto bufferTransform = (requestedCompositionType != hal::Composition::SOLID_COLOR &&
+                                  getState().overrideInfo.buffer == nullptr)
             ? outputDependentState.bufferTransform
             : static_cast<hal::Transform>(0);
     if (auto error = hwcLayer->setTransform(static_cast<hal::Transform>(bufferTransform));
@@ -431,11 +433,13 @@
         outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG);
     }
 
-    if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace);
-        error != hal::Error::NONE) {
-        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(),
-              outputDependentState.dataspace, to_string(error).c_str(),
-              static_cast<int32_t>(error));
+    const auto dataspace = outputDependentState.overrideInfo.buffer
+            ? outputDependentState.overrideInfo.dataspace
+            : outputDependentState.dataspace;
+
+    if (auto error = hwcLayer->setDataspace(dataspace); error != hal::Error::NONE) {
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(), dataspace,
+              to_string(error).c_str(), static_cast<int32_t>(error));
     }
 }
 
@@ -671,16 +675,26 @@
         return {};
     }
 
+    // Compute the geometry boundaries in layer stack space: we need to transform from the
+    // framebuffer space of the override buffer to layer space.
+    const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
+    const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
+    const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
+
     LayerFE::LayerSettings settings;
     settings.geometry = renderengine::Geometry{
-            .boundaries = getState().overrideInfo.displayFrame.toFloatRect(),
+            .boundaries = boundaries.toFloatRect(),
     };
     settings.bufferId = getState().overrideInfo.buffer->getId();
-    settings.source =
-            renderengine::PixelSource{.buffer = renderengine::Buffer{
-                                              .buffer = getState().overrideInfo.buffer,
-                                              .fence = getState().overrideInfo.acquireFence,
-                                      }};
+    settings.source = renderengine::PixelSource{
+            .buffer = renderengine::Buffer{
+                    .buffer = getState().overrideInfo.buffer,
+                    .fence = getState().overrideInfo.acquireFence,
+                    // If the transform from layer space to display space contains a rotation, we
+                    // need to undo the rotation in the texture transform
+                    .textureTransform =
+                            ui::Transform(transform.inverse().getOrientation(), 1, 1).asMatrix4(),
+            }};
     settings.sourceDataspace = getState().overrideInfo.dataspace;
     settings.alpha = 1.0f;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 45dce98..0f6804d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -72,6 +72,7 @@
     dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
     dumpVal(out, "override display frame", overrideInfo.displayFrame);
     dumpVal(out, "override dataspace", toString(overrideInfo.dataspace), overrideInfo.dataspace);
+    dumpVal(out, "override display space", to_string(overrideInfo.displaySpace));
 
     if (hwc) {
         dumpHwc(*hwc, out);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 4d3036a..f58addb 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -19,6 +19,7 @@
 // #define LOG_NDEBUG 0
 
 #include <android-base/properties.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/planner/CachedSet.h>
 #include <math/HashCombine.h>
 #include <renderengine/DisplaySettings.h>
@@ -50,10 +51,10 @@
 }
 
 CachedSet::Layer::Layer(const LayerState* state, std::chrono::steady_clock::time_point lastUpdate)
-      : mState(state), mHash(state->getHash(LayerStateField::Buffer)), mLastUpdate(lastUpdate) {}
+      : mState(state), mHash(state->getHash()), mLastUpdate(lastUpdate) {}
 
 CachedSet::CachedSet(const LayerState* layer, std::chrono::steady_clock::time_point lastUpdate)
-      : mFingerprint(layer->getHash(LayerStateField::Buffer)), mLastUpdate(lastUpdate) {
+      : mFingerprint(layer->getHash()), mLastUpdate(lastUpdate) {
     addLayer(layer, lastUpdate);
 }
 
@@ -84,6 +85,7 @@
     size_t hash = 0;
     android::hashCombineSingle(hash, mBounds);
     android::hashCombineSingle(hash, mOutputDataspace);
+    android::hashCombineSingle(hash, mOrientation);
     return hash;
 }
 
@@ -148,17 +150,22 @@
     }
 }
 
-void CachedSet::render(renderengine::RenderEngine& renderEngine, ui::Dataspace outputDataspace) {
+void CachedSet::render(renderengine::RenderEngine& renderEngine,
+                       const OutputCompositionState& outputState) {
+    const Rect& viewport = outputState.layerStackSpace.content;
+    const ui::Dataspace& outputDataspace = outputState.dataspace;
+    const ui::Transform::RotationFlags orientation =
+            ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
     renderengine::DisplaySettings displaySettings{
             .physicalDisplay = Rect(0, 0, mBounds.getWidth(), mBounds.getHeight()),
-            .clip = mBounds,
+            .clip = viewport,
             .outputDataspace = outputDataspace,
+            .orientation = orientation,
     };
 
     Region clearRegion = Region::INVALID_REGION;
-    Rect viewport = mBounds;
     LayerFE::ClientCompositionTargetSettings targetSettings{
-            .clip = Region(mBounds),
+            .clip = Region(viewport),
             .needsFiltering = false,
             .isSecure = true,
             .supportsProtectedContent = false,
@@ -216,7 +223,12 @@
     if (result == NO_ERROR) {
         mTexture.setBuffer(buffer, &renderEngine);
         mDrawFence = new Fence(drawFence.release());
+        mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(),
+                                                outputState.framebufferSpace.bounds.getHeight()),
+                                       mBounds);
+        mOutputSpace.orientation = outputState.framebufferSpace.orientation;
         mOutputDataspace = outputDataspace;
+        mOrientation = orientation;
     }
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 60ebbb2..aae49de 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -52,12 +52,12 @@
 }
 
 void Flattener::renderCachedSets(renderengine::RenderEngine& renderEngine,
-                                 ui::Dataspace outputDataspace) {
+                                 const OutputCompositionState& outputState) {
     if (!mNewCachedSet) {
         return;
     }
 
-    mNewCachedSet->render(renderEngine, outputDataspace);
+    mNewCachedSet->render(renderEngine, outputState);
 }
 
 void Flattener::dump(std::string& result) const {
@@ -193,9 +193,7 @@
     auto currentLayerIter = mLayers.begin();
     auto incomingLayerIter = layers.begin();
     while (incomingLayerIter != layers.end()) {
-        if (mNewCachedSet &&
-            mNewCachedSet->getFingerprint() ==
-                    (*incomingLayerIter)->getHash(LayerStateField::Buffer)) {
+        if (mNewCachedSet && mNewCachedSet->getFingerprint() == (*incomingLayerIter)->getHash()) {
             if (mNewCachedSet->hasBufferUpdate()) {
                 ALOGV("[%s] Dropping new cached set", __func__);
                 ++mInvalidatedCachedSetAges[0];
@@ -213,6 +211,7 @@
                                 .acquireFence = mNewCachedSet->getDrawFence(),
                                 .displayFrame = mNewCachedSet->getBounds(),
                                 .dataspace = mNewCachedSet->getOutputDataspace(),
+                                .displaySpace = mNewCachedSet->getOutputSpace(),
                         };
                         ++incomingLayerIter;
                     }
@@ -244,6 +243,7 @@
                         .acquireFence = currentLayerIter->getDrawFence(),
                         .displayFrame = currentLayerIter->getBounds(),
                         .dataspace = currentLayerIter->getOutputDataspace(),
+                        .displaySpace = currentLayerIter->getOutputSpace(),
                 };
                 ++incomingLayerIter;
             }
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index 222b2be..e976c9b 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -58,24 +58,24 @@
     return differences;
 }
 
-size_t LayerState::getHash(
-        Flags<LayerStateField> skipFields = static_cast<LayerStateField>(0)) const {
+size_t LayerState::getHash() const {
     size_t hash = 0;
     for (const StateInterface* field : getNonUniqueFields()) {
-        android::hashCombineSingleHashed(hash, field->getHash(skipFields));
+        if (field->getField() == LayerStateField::Buffer) {
+            continue;
+        }
+        android::hashCombineSingleHashed(hash, field->getHash());
     }
 
     return hash;
 }
 
-Flags<LayerStateField> LayerState::getDifferingFields(
-        const LayerState& other,
-        Flags<LayerStateField> skipFields = static_cast<LayerStateField>(0)) const {
+Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
     Flags<LayerStateField> differences;
     auto myFields = getNonUniqueFields();
     auto otherFields = other.getNonUniqueFields();
     for (size_t i = 0; i < myFields.size(); ++i) {
-        if (skipFields.test(myFields[i]->getField())) {
+        if (myFields[i]->getField() == LayerStateField::Buffer) {
             continue;
         }
 
@@ -169,7 +169,7 @@
 NonBufferHash getNonBufferHash(const std::vector<const LayerState*>& layers) {
     size_t hash = 0;
     for (const auto layer : layers) {
-        android::hashCombineSingleHashed(hash, layer->getHash(LayerStateField::Buffer));
+        android::hashCombineSingleHashed(hash, layer->getHash());
     }
 
     return hash;
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 87721c7..ad75557 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -134,8 +134,8 @@
 }
 
 void Planner::renderCachedSets(renderengine::RenderEngine& renderEngine,
-                               ui::Dataspace outputDataspace) {
-    mFlattener.renderCachedSets(renderEngine, outputDataspace);
+                               const OutputCompositionState& outputState) {
+    mFlattener.renderCachedSets(renderEngine, outputState);
 }
 
 void Planner::dump(const Vector<String16>& args, std::string& result) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
index 07920b8..8226ef7 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
@@ -33,8 +33,7 @@
     std::optional<ApproximateMatch> approximateMatch = {};
     for (size_t i = 0; i < mLayers.size(); ++i) {
         // Skip identical layers
-        if (mLayers[i].getHash(LayerStateField::Buffer) ==
-            other[i]->getHash(LayerStateField::Buffer)) {
+        if (mLayers[i].getHash() == other[i]->getHash()) {
             continue;
         }
 
@@ -56,8 +55,7 @@
             return std::nullopt;
         }
 
-        Flags<LayerStateField> differingFields =
-                mLayers[i].getDifferingFields(*other[i], LayerStateField::Buffer);
+        Flags<LayerStateField> differingFields = mLayers[i].getDifferingFields(*other[i]);
 
         // If we don't find an approximate match on this layer, then the LayerStacks differ
         // by too much, so return nothing
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 9dd199d..cbbc966 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -690,10 +690,12 @@
     static constexpr FloatRect kSourceCrop{11.f, 12.f, 13.f, 14.f};
     static constexpr uint32_t kZOrder = 21u;
     static constexpr Hwc2::Transform kBufferTransform = static_cast<Hwc2::Transform>(31);
+    static constexpr Hwc2::Transform kOverrideBufferTransform = static_cast<Hwc2::Transform>(0);
     static constexpr Hwc2::IComposerClient::BlendMode kBlendMode =
             static_cast<Hwc2::IComposerClient::BlendMode>(41);
     static constexpr float kAlpha = 51.f;
     static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
+    static constexpr ui::Dataspace kOverrideDataspace = static_cast<ui::Dataspace>(72);
     static constexpr int kSupportedPerFrameMetadata = 101;
     static constexpr int kExpectedHwcSlot = 0;
     static constexpr bool kLayerGenericMetadata1Mandatory = true;
@@ -701,13 +703,16 @@
 
     static const half4 kColor;
     static const Rect kDisplayFrame;
+    static const Rect kOverrideDisplayFrame;
     static const Region kOutputSpaceVisibleRegion;
     static const mat4 kColorTransform;
     static const Region kSurfaceDamage;
     static const HdrMetadata kHdrMetadata;
     static native_handle_t* kSidebandStreamHandle;
     static const sp<GraphicBuffer> kBuffer;
+    static const sp<GraphicBuffer> kOverrideBuffer;
     static const sp<Fence> kFence;
+    static const sp<Fence> kOverrideFence;
     static const std::string kLayerGenericMetadata1Key;
     static const std::vector<uint8_t> kLayerGenericMetadata1Value;
     static const std::string kLayerGenericMetadata2Key;
@@ -751,20 +756,32 @@
                                                              kLayerGenericMetadata2Value};
     }
 
-    void expectGeometryCommonCalls() {
-        EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
-        EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
+    void includeOverrideInfo() {
+        auto& overrideInfo = mOutputLayer.editState().overrideInfo;
+
+        overrideInfo.buffer = kOverrideBuffer;
+        overrideInfo.acquireFence = kOverrideFence;
+        overrideInfo.displayFrame = kOverrideDisplayFrame;
+        overrideInfo.dataspace = kOverrideDataspace;
+    }
+
+    void expectGeometryCommonCalls(Rect displayFrame = kDisplayFrame,
+                                   FloatRect sourceCrop = kSourceCrop,
+                                   Hwc2::Transform bufferTransform = kBufferTransform) {
+        EXPECT_CALL(*mHwcLayer, setDisplayFrame(displayFrame)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setSourceCrop(sourceCrop)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError));
-        EXPECT_CALL(*mHwcLayer, setTransform(kBufferTransform)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setTransform(bufferTransform)).WillOnce(Return(kError));
 
         EXPECT_CALL(*mHwcLayer, setBlendMode(kBlendMode)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setPlaneAlpha(kAlpha)).WillOnce(Return(kError));
     }
 
-    void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
+    void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None,
+                                   ui::Dataspace dataspace = kDataspace) {
         EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kOutputSpaceVisibleRegion)))
                 .WillOnce(Return(kError));
-        EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError));
+        EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
                 .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
                                          ? hal::Error::UNSUPPORTED
@@ -793,9 +810,10 @@
         EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
     }
 
-    void expectSetHdrMetadataAndBufferCalls() {
+    void expectSetHdrMetadataAndBufferCalls(sp<GraphicBuffer> buffer = kBuffer,
+                                            sp<Fence> fence = kFence) {
         EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
-        EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
+        EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, buffer, fence));
     }
 
     void expectGenericLayerMetadataCalls() {
@@ -817,6 +835,7 @@
 const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
                                                    84.f / 255.f};
 const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
+const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
 const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
         Rect{1005, 1006, 1007, 1008}};
 const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{
@@ -828,7 +847,9 @@
 native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle =
         reinterpret_cast<native_handle_t*>(1031);
 const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
+const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer = new GraphicBuffer();
 const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
+const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence();
 const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
         "com.example.metadata.1";
 const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}};
@@ -983,6 +1004,19 @@
     mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false);
 }
 
+TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    includeOverrideInfo();
+
+    expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideDisplayFrame.toFloatRect(),
+                              kOverrideBufferTransform);
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace);
+    expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence);
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false);
+}
+
 /*
  * OutputLayer::writeCursorPositionToHWC()
  */
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 7842efb..d3c4b1f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/planner/CachedSet.h>
 #include <compositionengine/impl/planner/LayerState.h>
 #include <compositionengine/mock/LayerFE.h>
@@ -59,6 +60,7 @@
 
     static constexpr size_t kNumLayers = 5;
     std::vector<std::unique_ptr<TestLayer>> mTestLayers;
+    impl::OutputCompositionState mOutputState;
 
     android::renderengine::mock::RenderEngine mRenderEngine;
 };
@@ -87,6 +89,12 @@
                 std::make_unique<CachedSet::Layer>(testLayer->layerState.get(), kStartTime);
 
         mTestLayers.emplace_back(std::move(testLayer));
+
+        // set up minimium params needed for rendering
+        mOutputState.dataspace = ui::Dataspace::SRGB;
+        mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(10, 5));
+        mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
+        mOutputState.layerStackSpace = ProjectionSpace(ui::Size(20, 10), Rect(5, 10));
     }
 }
 
@@ -288,7 +296,9 @@
                                 const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
                                 base::unique_fd*) -> size_t {
         EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay);
-        EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.clip);
+        EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
+        EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+                  displaySettings.orientation);
         EXPECT_EQ(0.5f, layers[0]->alpha);
         EXPECT_EQ(0.75f, layers[1]->alpha);
         EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
@@ -300,9 +310,14 @@
     EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
     EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
     EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_));
-    cachedSet.render(mRenderEngine, ui::Dataspace::SRGB);
+    cachedSet.render(mRenderEngine, mOutputState);
     expectReadyBuffer(cachedSet);
 
+    EXPECT_EQ(Rect(0, 0, 2, 2), cachedSet.getOutputSpace().content);
+    EXPECT_EQ(Rect(mOutputState.framebufferSpace.bounds.getWidth(),
+                   mOutputState.framebufferSpace.bounds.getHeight()),
+              cachedSet.getOutputSpace().bounds);
+
     // Now check that appending a new cached set properly cleans up RenderEngine resources.
     EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_));
     CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index bd77559..1bbf11a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/planner/CachedSet.h>
 #include <compositionengine/impl/planner/Flattener.h>
 #include <compositionengine/impl/planner/LayerState.h>
@@ -76,6 +77,7 @@
 
     static constexpr size_t kNumLayers = 5;
     std::vector<std::unique_ptr<TestLayer>> mTestLayers;
+    impl::OutputCompositionState mOutputState;
 };
 
 void FlattenerTest::SetUp() {
@@ -120,6 +122,11 @@
         testLayer->layerState->incrementFramesSinceBufferUpdate();
 
         mTestLayers.emplace_back(std::move(testLayer));
+
+        // set up minimium params needed for rendering
+        mOutputState.dataspace = ui::Dataspace::SRGB;
+        mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(10, 5));
+        mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
     }
 }
 
@@ -134,13 +141,13 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     // same geometry, update the internal layer stack
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 }
 
 void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
@@ -150,7 +157,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     for (const auto layer : layers) {
         EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -160,7 +167,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer;
     EXPECT_NE(nullptr, buffer);
@@ -195,7 +202,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 }
 
 TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
@@ -241,13 +248,37 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
     EXPECT_EQ(overrideBuffer2, overrideBuffer3);
 }
 
+TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsProjectionSpace) {
+    auto& layerState1 = mTestLayers[0]->layerState;
+    const auto& overrideDisplaySpace =
+            layerState1->getOutputLayer()->getState().overrideInfo.displaySpace;
+
+    auto& layerState2 = mTestLayers[1]->layerState;
+
+    const std::vector<const LayerState*> layers = {
+            layerState1.get(),
+            layerState2.get(),
+    };
+
+    initializeFlattener(layers);
+
+    // make all layers inactive
+    mTime += 200ms;
+    expectAllLayersFlattened(layers);
+    EXPECT_EQ(overrideDisplaySpace.bounds,
+              Rect(mOutputState.framebufferSpace.bounds.getWidth(),
+                   mOutputState.framebufferSpace.bounds.getHeight()));
+    EXPECT_EQ(overrideDisplaySpace.content, Rect(0, 0, 2, 2));
+    EXPECT_EQ(overrideDisplaySpace.orientation, mOutputState.framebufferSpace.orientation);
+}
+
 TEST_F(FlattenerTest, flattenLayers_addLayerToFlattenedCauseReset) {
     auto& layerState1 = mTestLayers[0]->layerState;
     const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
@@ -276,7 +307,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -313,7 +344,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -322,7 +353,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_NE(nullptr, overrideBuffer2);
@@ -335,7 +366,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_NE(nullptr, overrideBuffer2);
@@ -344,7 +375,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -386,7 +417,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_EQ(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_EQ(nullptr, overrideBuffer1);
     EXPECT_EQ(nullptr, overrideBuffer2);
@@ -399,7 +430,8 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -411,7 +443,8 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mOutputState.framebufferSpace.orientation = ui::ROTATION_180;
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -426,7 +459,7 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -437,7 +470,8 @@
     initializeOverrideBuffer(layers);
     EXPECT_NE(getNonBufferHash(layers),
               mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
-    mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
+    mOutputState.framebufferSpace.orientation = ui::ROTATION_270;
+    mFlattener->renderCachedSets(mRenderEngine, mOutputState);
 
     EXPECT_NE(nullptr, overrideBuffer1);
     EXPECT_EQ(overrideBuffer1, overrideBuffer2);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 8f235ab..d5a7234 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -129,20 +129,13 @@
     EXPECT_NE(mLayerState->getId(), otherLayerState->getId());
 
     // Id is a unique field, so it's not computed in the hash for a layer state.
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::Id),
-              otherLayerState->getHash(LayerStateField::Id));
+    EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash());
 
     // Similarly, Id cannot be included in differing fields.
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::Id));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::Id));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_FALSE(mLayerState->compare(*otherLayerState));
     EXPECT_FALSE(otherLayerState->compare(*mLayerState));
@@ -188,20 +181,13 @@
     EXPECT_NE(mLayerState->getName(), otherLayerState->getName());
 
     // Name is a unique field, so it's not computed in the hash for a layer state.
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::Name),
-              otherLayerState->getHash(LayerStateField::Name));
+    EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash());
 
     // Similarly, Name cannot be included in differing fields.
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::Name));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::Name));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_FALSE(mLayerState->compare(*otherLayerState));
     EXPECT_FALSE(otherLayerState->compare(*mLayerState));
@@ -253,19 +239,12 @@
 
     EXPECT_NE(mLayerState->getDisplayFrame(), otherLayerState->getDisplayFrame());
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::DisplayFrame),
-              otherLayerState->getHash(LayerStateField::DisplayFrame));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::DisplayFrame));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::DisplayFrame));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -337,34 +316,17 @@
 
     EXPECT_NE(mLayerState->getCompositionType(), otherLayerState->getCompositionType());
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::CompositionType),
-              otherLayerState->getHash(LayerStateField::CompositionType));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::CompositionType));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::CompositionType));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
 }
 
-TEST_F(LayerStateTest, getBuffer) {
-    OutputLayerCompositionState outputLayerCompositionState;
-    LayerFECompositionState layerFECompositionState;
-    layerFECompositionState.buffer = new GraphicBuffer();
-    setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
-                       layerFECompositionState);
-    mLayerState = std::make_unique<LayerState>(&mOutputLayer);
-    EXPECT_EQ(layerFECompositionState.buffer, mLayerState->getBuffer());
-}
-
 TEST_F(LayerStateTest, updateBuffer) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;
@@ -380,7 +342,6 @@
     setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
                        layerFECompositionStateTwo);
     Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
-    EXPECT_EQ(layerFECompositionStateTwo.buffer, mLayerState->getBuffer());
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
 }
 
@@ -399,21 +360,12 @@
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getBuffer(), otherLayerState->getBuffer());
-
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::Buffer),
-              otherLayerState->getHash(LayerStateField::Buffer));
-
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
+    // Buffers are not included in differing fields or in hashes.
+    EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash());
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::Buffer));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::Buffer));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     // Buffers are explicitly excluded from comparison
     EXPECT_FALSE(mLayerState->compare(*otherLayerState));
@@ -453,19 +405,12 @@
                        layerFECompositionState);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::SourceCrop),
-              otherLayerState->getHash(LayerStateField::SourceCrop));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::SourceCrop));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::SourceCrop));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -504,19 +449,12 @@
                        layerFECompositionState);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::ZOrder),
-              otherLayerState->getHash(LayerStateField::ZOrder));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::ZOrder));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::ZOrder));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -555,19 +493,12 @@
                        layerFECompositionState);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::BufferTransform),
-              otherLayerState->getHash(LayerStateField::BufferTransform));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::BufferTransform));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::BufferTransform));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -606,19 +537,12 @@
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::BlendMode),
-              otherLayerState->getHash(LayerStateField::BlendMode));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::BlendMode));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::BlendMode));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -657,19 +581,12 @@
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::Alpha),
-              otherLayerState->getHash(LayerStateField::Alpha));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::Alpha));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::Alpha));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -708,19 +625,12 @@
                        layerFECompositionState);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::VisibleRegion),
-              otherLayerState->getHash(LayerStateField::VisibleRegion));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::VisibleRegion));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::VisibleRegion));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -759,19 +669,12 @@
                        layerFECompositionState);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::Dataspace),
-              otherLayerState->getHash(LayerStateField::Dataspace));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::Dataspace));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::Dataspace));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -814,19 +717,12 @@
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::ColorTransform),
-              otherLayerState->getHash(LayerStateField::ColorTransform));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::ColorTransform));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::ColorTransform));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -865,19 +761,12 @@
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::SidebandStream),
-              otherLayerState->getHash(LayerStateField::SidebandStream));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::SidebandStream));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::SidebandStream));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
@@ -916,19 +805,12 @@
                        layerFECompositionStateTwo);
     auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
 
-    EXPECT_NE(mLayerState->getHash(LayerStateField::None),
-              otherLayerState->getHash(LayerStateField::None));
-    EXPECT_EQ(mLayerState->getHash(LayerStateField::SolidColor),
-              otherLayerState->getHash(LayerStateField::SolidColor));
+    EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash());
 
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              mLayerState->getDifferingFields(*otherLayerState, LayerStateField::SolidColor));
+              mLayerState->getDifferingFields(*otherLayerState));
     EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::None));
-    EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None),
-              otherLayerState->getDifferingFields(*mLayerState, LayerStateField::SolidColor));
+              otherLayerState->getDifferingFields(*mLayerState));
 
     EXPECT_TRUE(mLayerState->compare(*otherLayerState));
     EXPECT_TRUE(otherLayerState->compare(*mLayerState));
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index f7fc162..8d685cf 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -76,14 +76,14 @@
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
-    const auto limitedSize = limitFramebufferSize(size);
+    const auto limitedSize = limitSize(size);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
     mConsumer->setMaxAcquiredBufferCount(
             SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
 void FramebufferSurface::resizeBuffers(const ui::Size& newSize) {
-    const auto limitedSize = limitFramebufferSize(newSize);
+    const auto limitedSize = limitSize(newSize);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
 }
 
@@ -179,19 +179,23 @@
     }
 }
 
-ui::Size FramebufferSurface::limitFramebufferSize(const ui::Size& size) {
+ui::Size FramebufferSurface::limitSize(const ui::Size& size) {
+    return limitSizeInternal(size, mMaxSize);
+}
+
+ui::Size FramebufferSurface::limitSizeInternal(const ui::Size& size, const ui::Size& maxSize) {
     ui::Size limitedSize = size;
     bool wasLimited = false;
-    if (size.width > mMaxSize.width && mMaxSize.width != 0) {
+    if (size.width > maxSize.width && maxSize.width != 0) {
         const float aspectRatio = static_cast<float>(size.width) / size.height;
-        limitedSize.height = mMaxSize.width / aspectRatio;
-        limitedSize.width = mMaxSize.width;
+        limitedSize.height = maxSize.width / aspectRatio;
+        limitedSize.width = maxSize.width;
         wasLimited = true;
     }
-    if (size.height > mMaxSize.height && mMaxSize.height != 0) {
+    if (limitedSize.height > maxSize.height && maxSize.height != 0) {
         const float aspectRatio = static_cast<float>(size.width) / size.height;
-        limitedSize.height = mMaxSize.height;
-        limitedSize.width = mMaxSize.height * aspectRatio;
+        limitedSize.height = maxSize.height;
+        limitedSize.width = maxSize.height * aspectRatio;
         wasLimited = true;
     }
     ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]",
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 5d1e131..3123351 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -55,15 +55,20 @@
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
 private:
+    friend class FramebufferSurfaceTest;
+
+    // Limits the width and height by the maximum width specified.
+    ui::Size limitSize(const ui::Size&);
+
+    // Used for testing purposes.
+    static ui::Size limitSizeInternal(const ui::Size&, const ui::Size& maxSize);
+
     virtual ~FramebufferSurface() { }; // this class cannot be overloaded
 
     virtual void freeBufferLocked(int slotIndex);
 
     virtual void dumpLocked(String8& result, const char* prefix) const;
 
-    // Limits the width and height by the maximum width specified in the constructor.
-    ui::Size limitFramebufferSize(const ui::Size&);
-
     // nextBuffer waits for and then latches the next buffer from the
     // BufferQueue and releases the previously latched buffer to the
     // BufferQueue.  The new buffer is returned in the 'buffer' argument.
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 2784861..6485265 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -575,13 +575,9 @@
             }
         } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
             // Finish late, Present late
-            if (displayFrameJankType == JankType::None) {
-                // Display frame is not janky, so purely app's fault
-                mJankType |= JankType::AppDeadlineMissed;
-            } else {
-                // Propagate DisplayFrame's jankType if it is janky
-                mJankType |= displayFrameJankType;
-            }
+            mJankType |= JankType::AppDeadlineMissed;
+            // Propagate DisplayFrame's jankType if it is janky
+            mJankType |= displayFrameJankType;
         }
     }
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 84b4b23..1306409 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -753,6 +753,8 @@
         getRenderEngine().primeCache();
     }
 
+    getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
+
     // Inform native graphics APIs whether the present timestamp is supported:
 
     const bool presentFenceReliable =
@@ -2634,6 +2636,7 @@
 
     if (display->isPrimary()) {
         mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight());
+        getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
     }
 }
 
@@ -3457,7 +3460,7 @@
         sp<Layer> layer = nullptr;
         if (s.surface) {
             layer = fromHandleLocked(s.surface).promote();
-        } else if (acquireFenceChanged) {
+        } else if (s.hasBufferChanges()) {
             ALOGW("Transaction with buffer, but no Layer?");
             continue;
         }
@@ -3467,7 +3470,7 @@
 
         ATRACE_NAME(layer->getName().c_str());
 
-        if (acquireFenceChanged) {
+        if (s.hasBufferChanges()) {
             // If backpressure is enabled and we already have a buffer to commit, keep the
             // transaction in the queue.
             const bool hasPendingBuffer = pendingBuffers.find(s.surface) != pendingBuffers.end();
@@ -3550,7 +3553,7 @@
 
     // Check for incoming buffer updates and increment the pending buffer count.
     for (const auto& state : states) {
-        if ((state.state.what & layer_state_t::eAcquireFenceChanged) && (state.state.surface)) {
+        if (state.state.hasBufferChanges() && (state.state.surface)) {
             mBufferCountTracker.increment(state.state.surface->localBinder());
         }
     }
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 3c1b9d8..9f94c73 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -55,6 +55,7 @@
         "EventThreadTest.cpp",
         "FpsReporterTest.cpp",
         "FpsTest.cpp",
+        "FramebufferSurfaceTest.cpp",
         "FrameTimelineTest.cpp",
         "HWComposerTest.cpp",
         "OneShotTimerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index d1385c0..982252f 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -668,9 +668,10 @@
     Fps renderRate = Fps::fromPeriodNsecs(30);
 
     EXPECT_CALL(*mTimeStats,
-                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne,
-                                                                sLayerNameOne, JankType::Unknown,
-                                                                -1, -1, 25}));
+                incrementJankyFrames(
+                        TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
+                                                   JankType::Unknown | JankType::AppDeadlineMissed,
+                                                   -1, -1, 25}));
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
     int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
@@ -697,7 +698,7 @@
     EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::UnknownPresent);
 
     EXPECT_EQ(surfaceFrame1->getActuals().presentTime, 90);
-    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::Unknown);
+    EXPECT_EQ(surfaceFrame1->getJankType(), JankType::Unknown | JankType::AppDeadlineMissed);
 }
 
 /*
@@ -1699,9 +1700,9 @@
 }
 
 TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) {
-    // First frame - DisplayFrame is not janky. This should classify the SurfaceFrame as
+    // First frame - DisplayFrame is not janky. This should classify the SurfaceFrame as only
     // AppDeadlineMissed. Second frame - DisplayFrame is janky. This should propagate DisplayFrame's
-    // jank to the SurfaceFrame.
+    // jank to the SurfaceFrame along with AppDeadlineMissed.
 
     EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
     auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
@@ -1771,7 +1772,8 @@
     EXPECT_EQ(actuals2.presentTime, 60);
     EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
     EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
-    EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+    EXPECT_EQ(presentedSurfaceFrame2.getJankType(),
+              JankType::SurfaceFlingerCpuDeadlineMissed | JankType::AppDeadlineMissed);
 }
 
 TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) {
diff --git a/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp b/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp
new file mode 100644
index 0000000..b8df640
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 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 "DisplayHardware/FramebufferSurface.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+class FramebufferSurfaceTest : public testing::Test {
+public:
+    ui::Size limitSize(const ui::Size& size, const ui::Size maxSize) {
+        return FramebufferSurface::limitSizeInternal(size, maxSize);
+    }
+};
+
+TEST_F(FramebufferSurfaceTest, limitSize) {
+    const ui::Size kMaxSize(1920, 1080);
+    EXPECT_EQ(ui::Size(1920, 1080), limitSize({3840, 2160}, kMaxSize));
+    EXPECT_EQ(ui::Size(1920, 1080), limitSize({1920, 1080}, kMaxSize));
+    EXPECT_EQ(ui::Size(1920, 1012), limitSize({4096, 2160}, kMaxSize));
+    EXPECT_EQ(ui::Size(1080, 1080), limitSize({3840, 3840}, kMaxSize));
+    EXPECT_EQ(ui::Size(1280, 720), limitSize({1280, 720}, kMaxSize));
+}
+
+} // namespace android