Merge "TimeStats: remove the regex checks on layer name"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 4f7cdf3..3fa5430 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,6 +5,7 @@
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                include/input/
+               libs/binder/fuzzer/
                libs/binder/ndk/
                libs/graphicsenv/
                libs/gui/
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 89baf68..369c3de 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -300,12 +300,10 @@
  * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
  * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
  * is set, the vector only contains files that were written in the last 30 minutes.
- * If |limit_by_count| is set, the vector only contains the ten latest files.
  */
 static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
                                         const std::string& file_prefix,
-                                        bool limit_by_mtime,
-                                        bool limit_by_count = true) {
+                                        bool limit_by_mtime) {
     const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
 
     std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
@@ -349,15 +347,6 @@
         dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
     }
 
-    // Sort in descending modification time so that we only keep the newest
-    // reports if |limit_by_count| is true.
-    std::sort(dump_data.begin(), dump_data.end(),
-              [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
-
-    if (limit_by_count && dump_data.size() > 10) {
-        dump_data.erase(dump_data.begin() + 10, dump_data.end());
-    }
-
     return dump_data;
 }
 
@@ -1571,6 +1560,10 @@
         RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
     }
 
+    DumpFile("PSI cpu", "/proc/pressure/cpu");
+    DumpFile("PSI memory", "/proc/pressure/memory");
+    DumpFile("PSI io", "/proc/pressure/io");
+
     if (!DropRootUser()) {
         return Dumpstate::RunStatus::ERROR;
     }
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index dbbcdff..fbb01f5 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -214,8 +214,8 @@
         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
     }
 
-    static const char* getZipFilePath() {
-        return ds.GetPath(".zip").c_str();
+    static const std::string getZipFilePath() {
+        return ds.GetPath(".zip");
     }
 };
 std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
@@ -224,12 +224,12 @@
 std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
 
 TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
-    EXPECT_EQ(access(getZipFilePath(), F_OK), 0);
+    EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
 }
 
 TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
     struct stat st;
-    EXPECT_EQ(stat(getZipFilePath(), &st), 0);
+    EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
     EXPECT_GE(st.st_size, 3000000 /* 3MB */);
     EXPECT_LE(st.st_size, 30000000 /* 30MB */);
 }
@@ -248,7 +248,7 @@
   public:
     ZipArchiveHandle handle;
     void SetUp() {
-        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0);
+        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath().c_str(), &handle), 0);
     }
     void TearDown() {
         CloseArchive(handle);
@@ -312,7 +312,7 @@
 class BugreportSectionTest : public Test {
   public:
     static void SetUpTestCase() {
-        ParseSections(ZippedBugreportGenerationTest::getZipFilePath(),
+        ParseSections(ZippedBugreportGenerationTest::getZipFilePath().c_str(),
                       ZippedBugreportGenerationTest::sections.get());
     }
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 7eee749..838d11d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -303,6 +303,9 @@
 // Location of the apex image.
 static const char* kApexImage = "/system/framework/apex.art";
 
+// Phenotype property name for enabling profiling the boot class path.
+static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
+
 class RunDex2Oat : public ExecVHelper {
   public:
     RunDex2Oat(int zip_fd,
@@ -402,7 +405,15 @@
             server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                                  ENABLE_APEX_IMAGE,
                                                                  /*default_value=*/ "");
-        if (use_apex_image == "true") {
+
+        std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
+        profile_boot_class_path =
+            server_configurable_flags::GetServerConfigurableFlag(
+                RUNTIME_NATIVE_BOOT_NAMESPACE,
+                PROFILE_BOOT_CLASS_PATH,
+                /*default_value=*/ profile_boot_class_path);
+
+        if (use_apex_image == "true" || profile_boot_class_path == "true") {
           boot_image = StringPrintf("-Ximage:%s", kApexImage);
         } else {
           boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
@@ -709,8 +720,7 @@
                   const unique_fd& reference_profile_fd,
                   const std::vector<unique_fd>& apk_fds,
                   const std::vector<std::string>& dex_locations,
-                  bool copy_and_update,
-                  bool store_aggregation_counters) {
+                  bool copy_and_update) {
 
         // TODO(calin): Assume for now we run in the bg compile job (which is in
         // most of the invocation). With the current data flow, is not very easy or
@@ -742,10 +752,6 @@
             AddArg("--copy-and-update-profile-key");
         }
 
-        if (store_aggregation_counters) {
-            AddArg("--store-aggregation-counters");
-        }
-
         // Do not add after dex2oat_flags, they should override others for debugging.
         PrepareArgs(profman_bin);
     }
@@ -753,14 +759,12 @@
     void SetupMerge(const std::vector<unique_fd>& profiles_fd,
                     const unique_fd& reference_profile_fd,
                     const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
-                    const std::vector<std::string>& dex_locations = std::vector<std::string>(),
-                    bool store_aggregation_counters = false) {
+                    const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
         SetupArgs(profiles_fd,
                   reference_profile_fd,
                   apk_fds,
                   dex_locations,
-                  /*copy_and_update=*/false,
-                  store_aggregation_counters);
+                  /*copy_and_update=*/false);
     }
 
     void SetupCopyAndUpdate(unique_fd&& profile_fd,
@@ -777,8 +781,7 @@
                   reference_profile_fd_,
                   apk_fds_,
                   dex_locations,
-                  /*copy_and_update=*/true,
-                  /*store_aggregation_counters=*/false);
+                  /*copy_and_update=*/true);
     }
 
     void SetupDump(const std::vector<unique_fd>& profiles_fd,
@@ -792,8 +795,7 @@
                   reference_profile_fd,
                   apk_fds,
                   dex_locations,
-                  /*copy_and_update=*/false,
-                  /*store_aggregation_counters=*/false);
+                  /*copy_and_update=*/false);
     }
 
     void Exec() {
@@ -2828,8 +2830,7 @@
         args.SetupMerge(profiles_fd,
                         snapshot_fd,
                         apk_fds,
-                        dex_locations,
-                        /*store_aggregation_counters=*/true);
+                        dex_locations);
         pid_t pid = fork();
         if (pid == 0) {
             /* child -- drop privileges before continuing */
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index db09070..5a5cb53 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -67,29 +67,29 @@
 }
 
 static void mkdir(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::mkdir(fullPath, 0755);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    ::mkdir(fullPath.c_str(), 0755);
 }
 
 static void touch(const char* path, int len, int time) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    int fd = ::open(fullPath.c_str(), O_RDWR | O_CREAT, 0644);
     ::fallocate(fd, 0, 0, len);
     ::close(fd);
     struct utimbuf times;
     times.actime = times.modtime = std::time(0) + time;
-    ::utime(fullPath, &times);
+    ::utime(fullPath.c_str(), &times);
 }
 
 static int exists(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    return ::access(fullPath, F_OK);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    return ::access(fullPath.c_str(), F_OK);
 }
 
 static int64_t size(const char* path) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
     struct stat buf;
-    if (!stat(fullPath, &buf)) {
+    if (!stat(fullPath.c_str(), &buf)) {
         return buf.st_size;
     } else {
         return -1;
@@ -107,8 +107,8 @@
 }
 
 static void setxattr(const char* path, const char* key) {
-    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
-    ::setxattr(fullPath, key, "", 0, 0);
+    const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
+    ::setxattr(fullPath.c_str(), key, "", 0, 0);
 }
 
 class CacheTest : public testing::Test {
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index 606477f..b7e520f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -137,7 +137,7 @@
 
 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
     char *tctx = nullptr;
-    if (selabel_lookup(getSehandle(), &tctx, name.c_str(), 0) != 0) {
+    if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
         LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
         return false;
     }
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 479e9b8..bbb3193 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -101,6 +101,7 @@
     OMX_IndexConfigOperatingRate,                   /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
     OMX_IndexParamConsumerUsageBits,                /**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexConfigLatency,                         /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigLowLatency,                      /**< reference: OMX_CONFIG_BOOLEANTYPE */
     OMX_IndexExtOtherEndUnused,
 
     /* Time configurations */
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 296e3f6..643a956 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,7 +71,12 @@
     // libbinder does not offer a stable wire protocol.
     // if a second copy of it is installed, then it may break after security
     // or dessert updates. Instead, apex users should use libbinder_ndk.
-    no_apex: true,
+    apex_available: [
+        "//apex_available:platform",
+        // TODO(b/139016109) remove these three
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
 
     srcs: [
         "Binder.cpp",
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ee637e2..a30df14 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -43,6 +43,47 @@
 using AidlServiceManager = android::os::IServiceManager;
 using android::binder::Status;
 
+// libbinder's IServiceManager.h can't rely on the values generated by AIDL
+// because many places use its headers via include_dirs (meaning, without
+// declaring the dependency in the build system). So, for now, we can just check
+// the values here.
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_CRITICAL == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_HIGH == IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_NORMAL == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_DEFAULT == IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+static_assert(AidlServiceManager::DUMP_FLAG_PRIORITY_ALL == IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+static_assert(AidlServiceManager::DUMP_FLAG_PROTO == IServiceManager::DUMP_FLAG_PROTO);
+
+const String16& IServiceManager::getInterfaceDescriptor() const {
+    return AidlServiceManager::descriptor;
+}
+IServiceManager::IServiceManager() {}
+IServiceManager::~IServiceManager() {}
+
+// From the old libbinder IServiceManager interface to IServiceManager.
+class ServiceManagerShim : public IServiceManager
+{
+public:
+    explicit ServiceManagerShim (const sp<AidlServiceManager>& impl);
+
+    sp<IBinder> getService(const String16& name) const override;
+    sp<IBinder> checkService(const String16& name) const override;
+    status_t addService(const String16& name, const sp<IBinder>& service,
+                        bool allowIsolated, int dumpsysPriority) override;
+    Vector<String16> listServices(int dumpsysPriority) override;
+    sp<IBinder> waitForService(const String16& name16) override;
+
+    // for legacy ABI
+    const String16& getInterfaceDescriptor() const override {
+        return mTheRealServiceManager->getInterfaceDescriptor();
+    }
+    IBinder* onAsBinder() override {
+        return IInterface::asBinder(mTheRealServiceManager).get();
+    }
+private:
+    sp<AidlServiceManager> mTheRealServiceManager;
+};
+
 sp<IServiceManager> defaultServiceManager()
 {
     static Mutex gDefaultServiceManagerLock;
@@ -53,8 +94,9 @@
     {
         AutoMutex _l(gDefaultServiceManagerLock);
         while (gDefaultServiceManager == nullptr) {
-            gDefaultServiceManager = interface_cast<IServiceManager>(
-                ProcessState::self()->getContextObject(nullptr));
+            gDefaultServiceManager = new ServiceManagerShim(
+                interface_cast<AidlServiceManager>(
+                    ProcessState::self()->getContextObject(nullptr)));
             if (gDefaultServiceManager == nullptr)
                 sleep(1);
         }
@@ -147,142 +189,136 @@
 
 // ----------------------------------------------------------------------
 
-class BpServiceManager : public BpInterface<IServiceManager>
-{
-public:
-    explicit BpServiceManager(const sp<IBinder>& impl)
-        : BpInterface<IServiceManager>(impl),
-          mTheRealServiceManager(interface_cast<AidlServiceManager>(impl))
-    {
-    }
+ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
+ : mTheRealServiceManager(impl)
+{}
 
-    sp<IBinder> getService(const String16& name) const override
-    {
-        static bool gSystemBootCompleted = false;
+sp<IBinder> ServiceManagerShim::getService(const String16& name) const
+{
+    static bool gSystemBootCompleted = false;
+
+    sp<IBinder> svc = checkService(name);
+    if (svc != nullptr) return svc;
+
+    const bool isVendorService =
+        strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+    const long timeout = uptimeMillis() + 5000;
+    // Vendor code can't access system properties
+    if (!gSystemBootCompleted && !isVendorService) {
+#ifdef __ANDROID__
+        char bootCompleted[PROPERTY_VALUE_MAX];
+        property_get("sys.boot_completed", bootCompleted, "0");
+        gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
+#else
+        gSystemBootCompleted = true;
+#endif
+    }
+    // retry interval in millisecond; note that vendor services stay at 100ms
+    const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+    int n = 0;
+    while (uptimeMillis() < timeout) {
+        n++;
+        ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+            ProcessState::self()->getDriverName().c_str());
+        usleep(1000*sleepTime);
 
         sp<IBinder> svc = checkService(name);
         if (svc != nullptr) return svc;
+    }
+    ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+    return nullptr;
+}
 
-        const bool isVendorService =
-            strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
-        const long timeout = uptimeMillis() + 5000;
-        // Vendor code can't access system properties
-        if (!gSystemBootCompleted && !isVendorService) {
-#ifdef __ANDROID__
-            char bootCompleted[PROPERTY_VALUE_MAX];
-            property_get("sys.boot_completed", bootCompleted, "0");
-            gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
-#else
-            gSystemBootCompleted = true;
-#endif
+sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
+{
+    sp<IBinder> ret;
+    if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
+        return nullptr;
+    }
+    return ret;
+}
+
+status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
+                                        bool allowIsolated, int dumpsysPriority)
+{
+    Status status = mTheRealServiceManager->addService(
+        String8(name).c_str(), service, allowIsolated, dumpsysPriority);
+    return status.exceptionCode();
+}
+
+Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
+{
+    std::vector<std::string> ret;
+    if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
+        return {};
+    }
+
+    Vector<String16> res;
+    res.setCapacity(ret.size());
+    for (const std::string& name : ret) {
+        res.push(String16(name.c_str()));
+    }
+    return res;
+}
+
+sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
+{
+    class Waiter : public android::os::BnServiceCallback {
+        Status onRegistration(const std::string& /*name*/,
+                              const sp<IBinder>& binder) override {
+            std::unique_lock<std::mutex> lock(mMutex);
+            mBinder = binder;
+            lock.unlock();
+            mCv.notify_one();
+            return Status::ok();
         }
-        // retry interval in millisecond; note that vendor services stay at 100ms
-        const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+    public:
+        sp<IBinder> mBinder;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+    };
 
-        int n = 0;
-        while (uptimeMillis() < timeout) {
-            n++;
-            ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
-                ProcessState::self()->getDriverName().c_str());
-            usleep(1000*sleepTime);
+    const std::string name = String8(name16).c_str();
 
-            sp<IBinder> svc = checkService(name);
-            if (svc != nullptr) return svc;
-        }
-        ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
+    sp<IBinder> out;
+    if (!mTheRealServiceManager->getService(name, &out).isOk()) {
+        return nullptr;
+    }
+    if(out != nullptr) return out;
+
+    sp<Waiter> waiter = new Waiter;
+    if (!mTheRealServiceManager->registerForNotifications(
+            name, waiter).isOk()) {
         return nullptr;
     }
 
-    sp<IBinder> checkService(const String16& name) const override {
-        sp<IBinder> ret;
-        if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
-            return nullptr;
-        }
-        return ret;
-    }
-
-    status_t addService(const String16& name, const sp<IBinder>& service,
-                        bool allowIsolated, int dumpsysPriority) override {
-        Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority);
-        return status.exceptionCode();
-    }
-
-    virtual Vector<String16> listServices(int dumpsysPriority) {
-        std::vector<std::string> ret;
-        if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
-            return {};
+    while(true) {
+        {
+            std::unique_lock<std::mutex> lock(waiter->mMutex);
+            using std::literals::chrono_literals::operator""s;
+            waiter->mCv.wait_for(lock, 1s, [&] {
+                return waiter->mBinder != nullptr;
+            });
+            if (waiter->mBinder != nullptr) return waiter->mBinder;
         }
 
-        Vector<String16> res;
-        res.setCapacity(ret.size());
-        for (const std::string& name : ret) {
-            res.push(String16(name.c_str()));
-        }
-        return res;
-    }
-
-    sp<IBinder> waitForService(const String16& name16) override {
-        class Waiter : public android::os::BnServiceCallback {
-            Status onRegistration(const std::string& /*name*/,
-                                  const sp<IBinder>& binder) override {
-                std::unique_lock<std::mutex> lock(mMutex);
-                mBinder = binder;
-                lock.unlock();
-                mCv.notify_one();
-                return Status::ok();
-            }
-        public:
-            sp<IBinder> mBinder;
-            std::mutex mMutex;
-            std::condition_variable mCv;
-        };
-
-        const std::string name = String8(name16).c_str();
-
-        sp<IBinder> out;
+        // Handle race condition for lazy services. Here is what can happen:
+        // - the service dies (not processed by init yet).
+        // - sm processes death notification.
+        // - sm gets getService and calls init to start service.
+        // - init gets the start signal, but the service already appears
+        //   started, so it does nothing.
+        // - init gets death signal, but doesn't know it needs to restart
+        //   the service
+        // - we need to request service again to get it to start
         if (!mTheRealServiceManager->getService(name, &out).isOk()) {
             return nullptr;
         }
         if(out != nullptr) return out;
 
-        sp<Waiter> waiter = new Waiter;
-        if (!mTheRealServiceManager->registerForNotifications(
-                name, waiter).isOk()) {
-            return nullptr;
-        }
-
-        while(true) {
-            {
-                std::unique_lock<std::mutex> lock(waiter->mMutex);
-                using std::literals::chrono_literals::operator""s;
-                waiter->mCv.wait_for(lock, 1s, [&] {
-                    return waiter->mBinder != nullptr;
-                });
-                if (waiter->mBinder != nullptr) return waiter->mBinder;
-            }
-
-            // Handle race condition for lazy services. Here is what can happen:
-            // - the service dies (not processed by init yet).
-            // - sm processes death notification.
-            // - sm gets getService and calls init to start service.
-            // - init gets the start signal, but the service already appears
-            //   started, so it does nothing.
-            // - init gets death signal, but doesn't know it needs to restart
-            //   the service
-            // - we need to request service again to get it to start
-            if (!mTheRealServiceManager->getService(name, &out).isOk()) {
-                return nullptr;
-            }
-            if(out != nullptr) return out;
-
-            ALOGW("Waited one second for %s", name.c_str());
-        }
+        ALOGW("Waited one second for %s", name.c_str());
     }
-
-private:
-    sp<AidlServiceManager> mTheRealServiceManager;
-};
-
-IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+}
 
 } // namespace android
diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/fuzzer/Android.bp
index f3e4229..d2f0d37 100644
--- a/libs/binder/fuzzer/Android.bp
+++ b/libs/binder/fuzzer/Android.bp
@@ -1,8 +1,10 @@
 cc_fuzz {
     name: "binder_parcel_fuzzer",
+    defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
     srcs: [
         "binder.cpp",
+        "binder_ndk.cpp",
         "hwbinder.cpp",
         "main.cpp",
         "util.cpp",
@@ -22,10 +24,16 @@
 
     target: {
         android: {
-            shared_libs: ["libbinder"],
+            shared_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
         },
         host: {
-            static_libs: ["libbinder"],
+            static_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
         },
     },
 }
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index ce21178..86264db 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/fuzzer/binder.cpp
@@ -18,8 +18,48 @@
 #include "binder.h"
 #include "util.h"
 
+#include <android/os/IServiceManager.h>
+
 using ::android::status_t;
 
+class ExampleParcelable : public android::Parcelable {
+public:
+    status_t writeToParcel(android::Parcel* /*parcel*/) const override {
+        FUZZ_LOG() << "should not reach";
+        abort();
+    }
+    status_t readFromParcel(const android::Parcel* parcel) override {
+        mExampleExtraField++;
+        return parcel->readInt64(&(this->mExampleUsedData));
+    }
+private:
+    int64_t mExampleExtraField = 0;
+    int64_t mExampleUsedData = 0;
+};
+
+struct ExampleFlattenable : public android::Flattenable<ExampleFlattenable> {
+public:
+    size_t getFlattenedSize() const { return sizeof(mValue); }
+    size_t getFdCount() const { return 0; }
+    status_t flatten(void*& /*buffer*/, size_t& /*size*/, int*& /*fds*/, size_t& /*count*/) const {
+        FUZZ_LOG() << "should not reach";
+        abort();
+    }
+    status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+        if (size < sizeof(mValue)) {
+            return android::NO_MEMORY;
+        }
+        android::FlattenableUtils::read(buffer, size, mValue);
+        return android::OK;
+    }
+private:
+    int32_t mValue = 0xFEEDBEEF;
+};
+
+struct ExampleLightFlattenable : public android::LightFlattenablePod<ExampleLightFlattenable> {
+    int32_t mValue = 0;
+};
+
 #define PARCEL_READ_WITH_STATUS(T, FUN) \
     [] (const ::android::Parcel& p, uint8_t /*data*/) {\
         FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
@@ -85,7 +125,7 @@
     [] (const ::android::Parcel& p, uint8_t len) {
         FUZZ_LOG() << "about to readInplace";
         const void* r = p.readInplace(len);
-        FUZZ_LOG() << "readInplace done. pointer: " << r;
+        FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << hexString(r, len);
     },
     PARCEL_READ_OPT_STATUS(int32_t, readInt32),
     PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
@@ -108,13 +148,26 @@
     PARCEL_READ_OPT_STATUS(android::String8, readString8),
     PARCEL_READ_OPT_STATUS(android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
-    // TODO: readString16Inplace
+    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+        FUZZ_LOG() << "about to readString16Inplace";
+        size_t outLen = 0;
+        const char16_t* str = p.readString16Inplace(&outLen);
+        FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outLen)
+                   << " size: " << outLen;
+    },
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readNullableStrongBinder),
 
-    // TODO: all templated versions of readParcelableVector, readParcelable
-    // TODO: readParcelable
-    // TODO: templated versions of readStrongBinder, readNullableStrongBinder
+    // only reading one parcelable type for now
+    // TODO(b/131868573): can force read of arbitrarily sized vector
+    // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
+    // PARCEL_READ_WITH_STATUS(std::vector<ExampleParcelable>, readParcelableVector),
+    PARCEL_READ_WITH_STATUS(ExampleParcelable, readParcelable),
+    PARCEL_READ_WITH_STATUS(std::unique_ptr<ExampleParcelable>, readParcelable),
+
+    // only reading one binder type for now
+    PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
+    PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readNullableStrongBinder),
 
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
@@ -144,12 +197,34 @@
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<std::string>>>, readUtf8VectorFromUtf16Vector),
     // PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
 
-    // TODO: read(Flattenable<T>)
-    // TODO: read(LightFlattenable<T>)
+    [] (const android::Parcel& p, uint8_t /*len*/) {
+        FUZZ_LOG() << "about to read flattenable";
+        ExampleFlattenable f;
+        status_t status = p.read(f);
+        FUZZ_LOG() << "read flattenable: " << status;
+    },
+    [] (const android::Parcel& p, uint8_t /*len*/) {
+        FUZZ_LOG() << "about to read lite flattenable";
+        ExampleLightFlattenable f;
+        status_t status = p.read(f);
+        FUZZ_LOG() << "read lite flattenable: " << status;
+    },
+
+    // TODO(b/131868573): can force read of arbitrarily sized vector
     // TODO: resizeOutVector
 
     PARCEL_READ_NO_STATUS(int32_t, readExceptionCode),
-    // TODO: readNativeHandle
+    [] (const android::Parcel& p, uint8_t /*len*/) {
+        FUZZ_LOG() << "about to readNativeHandle";
+        native_handle_t* t = p.readNativeHandle();
+        FUZZ_LOG() << "readNativeHandle: " << t;
+        if (t != nullptr) {
+            FUZZ_LOG() << "about to free readNativeHandle";
+            native_handle_close(t);
+            native_handle_delete(t);
+            FUZZ_LOG() << "readNativeHandle freed";
+        }
+    },
     PARCEL_READ_NO_STATUS(int, readFileDescriptor),
     PARCEL_READ_NO_STATUS(int, readParcelFileDescriptor),
     PARCEL_READ_WITH_STATUS(android::base::unique_fd, readUniqueFileDescriptor),
@@ -164,7 +239,12 @@
         status_t status = p.readBlob(len, &blob);
         FUZZ_LOG() << "readBlob status: " << status;
     },
-    // TODO: readObject
+    [] (const android::Parcel& p, uint8_t options) {
+        FUZZ_LOG() << "about to readObject";
+        bool nullMetaData = options & 0x1;
+        const void* obj = static_cast<const void*>(p.readObject(nullMetaData));
+        FUZZ_LOG() << "readObject: " << obj;
+    },
     PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
     PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
diff --git a/libs/binder/fuzzer/binder.h b/libs/binder/fuzzer/binder.h
index 32dcc79..b224ef4 100644
--- a/libs/binder/fuzzer/binder.h
+++ b/libs/binder/fuzzer/binder.h
@@ -17,6 +17,6 @@
 #include <binder/Parcel.h>
 #include <vector>
 
-#include "parcel.h"
+#include "parcel_fuzzer.h"
 
 extern std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/binder_ndk.cpp b/libs/binder/fuzzer/binder_ndk.cpp
new file mode 100644
index 0000000..29da8f7
--- /dev/null
+++ b/libs/binder/fuzzer/binder_ndk.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define FUZZ_LOG_TAG "binder_ndk"
+
+#include "binder_ndk.h"
+
+#include <android/binder_parcel_utils.h>
+
+#include "util.h"
+
+// TODO(b/142061461): parent class
+class SomeParcelable {
+public:
+    binder_status_t readFromParcel(const AParcel* parcel) {
+        return AParcel_readInt32(parcel, &mValue);
+    }
+
+private:
+    int32_t mValue = 0;
+};
+
+#define PARCEL_READ(T, FUN)                                              \
+    [](const NdkParcelAdapter& p, uint8_t /*data*/) {                    \
+        FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
+        T t{};                                                           \
+        binder_status_t status = FUN(p.aParcel(), &t);                   \
+        FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;  \
+    }
+
+// clang-format off
+std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS{
+        // methods from binder_parcel.h
+        [](const NdkParcelAdapter& p, uint8_t pos) {
+            FUZZ_LOG() << "about to set data position to " << pos;
+            binder_status_t status = AParcel_setDataPosition(p.aParcel(), pos);
+            FUZZ_LOG() << "set data position: " << status;
+        },
+        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+            FUZZ_LOG() << "about to read status header";
+            ndk::ScopedAStatus t;
+            binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
+            FUZZ_LOG() << "read status header: " << status;
+        },
+        PARCEL_READ(int32_t, AParcel_readInt32),
+        PARCEL_READ(uint32_t, AParcel_readUint32),
+        PARCEL_READ(int64_t, AParcel_readInt64),
+        PARCEL_READ(uint64_t, AParcel_readUint64),
+        PARCEL_READ(float, AParcel_readFloat),
+        PARCEL_READ(double, AParcel_readDouble),
+        PARCEL_READ(bool, AParcel_readBool),
+        PARCEL_READ(char16_t, AParcel_readChar),
+        PARCEL_READ(int8_t, AParcel_readByte),
+
+        // methods from binder_parcel_utils.h
+        PARCEL_READ(ndk::SpAIBinder, ndk::AParcel_readNullableStrongBinder),
+        PARCEL_READ(ndk::SpAIBinder, ndk::AParcel_readRequiredStrongBinder),
+        PARCEL_READ(ndk::ScopedFileDescriptor, ndk::AParcel_readNullableParcelFileDescriptor),
+        PARCEL_READ(ndk::ScopedFileDescriptor, ndk::AParcel_readRequiredParcelFileDescriptor),
+        PARCEL_READ(std::string, ndk::AParcel_readString),
+        PARCEL_READ(std::optional<std::string>, ndk::AParcel_readString),
+        // TODO(b/131868573): can force process to allocate arbitrary amount of
+        // memory
+        // PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>,
+        // ndk::AParcel_readVector), PARCEL_READ(std::vector<SomeParcelable>,
+        // ndk::AParcel_readVector), PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<uint32_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<int64_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<int64_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<uint64_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<uint64_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<float>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<float>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<double>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<double>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<bool>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<bool>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<char16_t>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::optional<std::vector<char16_t>>, ndk::AParcel_readVector),
+        // PARCEL_READ(std::vector<int32_t>, ndk::AParcel_resizeVector),
+        // PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_resizeVector),
+};
+// clang-format on
diff --git a/libs/binder/fuzzer/binder_ndk.h b/libs/binder/fuzzer/binder_ndk.h
new file mode 100644
index 0000000..622cafc
--- /dev/null
+++ b/libs/binder/fuzzer/binder_ndk.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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 <android/binder_auto_utils.h>
+#include <vector>
+
+#include <android/binder_parcel.h>
+#include "parcel_fuzzer.h"
+
+// libbinder_ndk doesn't export this header which breaks down its API for NDK
+// and APEX users, but we need access to it to fuzz.
+#include "../ndk/parcel_internal.h"
+
+class NdkParcelAdapter {
+public:
+    NdkParcelAdapter() : mParcel(new AParcel(nullptr /*binder*/)) {}
+
+    const AParcel* aParcel() const { return mParcel.get(); }
+    AParcel* aParcel() { return mParcel.get(); }
+
+    size_t dataSize() const { return aParcel()->get()->dataSize(); }
+    size_t dataAvail() const { return aParcel()->get()->dataAvail(); }
+    size_t dataPosition() const { return aParcel()->get()->dataPosition(); }
+    size_t dataCapacity() const { return aParcel()->get()->dataCapacity(); }
+    android::status_t setData(const uint8_t* buffer, size_t len) {
+        return aParcel()->get()->setData(buffer, len);
+    }
+
+private:
+    ndk::ScopedAParcel mParcel;
+};
+
+extern std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/hwbinder.h b/libs/binder/fuzzer/hwbinder.h
index 03ab510..a6c66be 100644
--- a/libs/binder/fuzzer/hwbinder.h
+++ b/libs/binder/fuzzer/hwbinder.h
@@ -17,6 +17,6 @@
 #include <hwbinder/Parcel.h>
 #include <vector>
 
-#include "parcel.h"
+#include "parcel_fuzzer.h"
 
 extern std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/main.cpp b/libs/binder/fuzzer/main.cpp
index 03fde3a..369aa34 100644
--- a/libs/binder/fuzzer/main.cpp
+++ b/libs/binder/fuzzer/main.cpp
@@ -16,6 +16,7 @@
 #define FUZZ_LOG_TAG "main"
 
 #include "binder.h"
+#include "binder_ndk.h"
 #include "hwbinder.h"
 #include "util.h"
 
@@ -50,6 +51,7 @@
     // although they will do completely different things, might as well fuzz both
     doFuzz<::android::hardware::Parcel>(HWBINDER_PARCEL_READ_FUNCTIONS, input, instructions);
     doFuzz<::android::Parcel>(BINDER_PARCEL_READ_FUNCTIONS, input, instructions);
+    doFuzz<NdkParcelAdapter>(BINDER_NDK_PARCEL_READ_FUNCTIONS, input, instructions);
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
diff --git a/libs/binder/fuzzer/parcel.h b/libs/binder/fuzzer/parcel_fuzzer.h
similarity index 99%
rename from libs/binder/fuzzer/parcel.h
rename to libs/binder/fuzzer/parcel_fuzzer.h
index 5f05335..10cf17c 100644
--- a/libs/binder/fuzzer/parcel.h
+++ b/libs/binder/fuzzer/parcel_fuzzer.h
@@ -16,5 +16,3 @@
 
 template <typename P>
 using ParcelRead = std::function<void(const P& p, uint8_t data)>;
-
-
diff --git a/libs/binder/fuzzer/util.cpp b/libs/binder/fuzzer/util.cpp
index b3a4ee7..b1213e9 100644
--- a/libs/binder/fuzzer/util.cpp
+++ b/libs/binder/fuzzer/util.cpp
@@ -21,11 +21,17 @@
 #include <iomanip>
 #include <sstream>
 
-std::string hexString(const std::vector<uint8_t>& hash) {
+std::string hexString(const void* bytes, size_t len) {
+    if (bytes == nullptr) return "<null>";
+
     std::ostringstream s;
     s << std::hex << std::setfill('0');
-    for (uint8_t i : hash) {
-        s << std::setw(2) << static_cast<int>(i);
+    for (size_t i = 0; i < len; i++) {
+        s << std::setw(2) << static_cast<int>(
+            static_cast<const uint8_t*>(bytes)[i]);
     }
     return s.str();
 }
+std::string hexString(const std::vector<uint8_t>& bytes) {
+    return hexString(bytes.data(), bytes.size());
+}
diff --git a/libs/binder/fuzzer/util.h b/libs/binder/fuzzer/util.h
index 07e68a8..416c3a7 100644
--- a/libs/binder/fuzzer/util.h
+++ b/libs/binder/fuzzer/util.h
@@ -45,4 +45,5 @@
     std::stringstream mOs;
 };
 
-std::string hexString(const std::vector<uint8_t>& hash);
+std::string hexString(const void* bytes, size_t len);
+std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 5793a1c..28ffa48 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -88,8 +88,12 @@
 public:                                                                 \
 
 
+#define __IINTF_CONCAT(x, y) (x ## y)
 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
-    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
+    const ::android::StaticString16                                     \
+        I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
+    const ::android::String16 I##INTERFACE::descriptor(                 \
+        I##INTERFACE##_descriptor_static_str16);                        \
     const ::android::String16&                                          \
             I##INTERFACE::getInterfaceDescriptor() const {              \
         return I##INTERFACE::descriptor;                                \
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index def1bea..a675513 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -26,12 +26,22 @@
 
 // ----------------------------------------------------------------------
 
+/**
+ * Service manager for C++ services.
+ *
+ * IInterface is only for legacy ABI compatibility
+ */
 class IServiceManager : public IInterface
 {
 public:
-    DECLARE_META_INTERFACE(ServiceManager)
+    // for ABI compatibility
+    virtual const String16& getInterfaceDescriptor() const;
+
+    IServiceManager();
+    virtual ~IServiceManager();
+
     /**
-     * Must match values in IServiceManager.java
+     * Must match values in IServiceManager.aidl
      */
     /* Allows services to dump sections according to priorities. */
     static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 62a0f9f..22344b6 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -27,7 +27,7 @@
     },
 }
 
-cc_library_shared {
+cc_library {
     name: "libbinder_ndk",
 
     defaults: ["libbinder_ndk_host_user"],
@@ -69,6 +69,12 @@
     ],
 
     target: {
+        android: {
+            // Only one copy of this library on an Android device
+            static: {
+                enabled: false,
+            },
+        },
         linux: {
             version_script: "libbinder_ndk.map.txt",
         },
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 9080ce1..a8f7d92 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -8,6 +8,7 @@
         "liblog",
         "libnetdutils"
     ],
+    header_libs: ["bpf_prog_headers"],
     cflags: [
         "-Werror",
         "-Wall",
@@ -25,6 +26,7 @@
         "libtimeinstate",
         "libnetdutils",
     ],
+    header_libs: ["bpf_prog_headers"],
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index f255512..45fea85 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "libtimeinstate"
 
 #include "cputimeinstate.h"
-#include "timeinstate.h"
+#include <bpf_timeinstate.h>
 
 #include <dirent.h>
 #include <errno.h>
@@ -110,9 +110,10 @@
             std::string path =
                     StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
             auto nums = readNumbersFromFile(path);
-            if (!nums) return false;
+            if (!nums) continue;
             freqs.insert(freqs.end(), nums->begin(), nums->end());
         }
+        if (freqs.empty()) return false;
         std::sort(freqs.begin(), freqs.end());
         gPolicyFreqs.emplace_back(freqs);
 
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 15f6214..c0cd3e0 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,5 +1,5 @@
 
-#include "timeinstate.h"
+#include <bpf_timeinstate.h>
 
 #include <sys/sysinfo.h>
 
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
deleted file mode 100644
index 6d4f913..0000000
--- a/libs/cputimeinstate/timeinstate.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 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 <inttypes.h>
-
-#define BPF_FS_PATH "/sys/fs/bpf/"
-
-#define FREQS_PER_ENTRY 32
-#define CPUS_PER_ENTRY 8
-
-struct time_key_t {
-    uint32_t uid;
-    uint32_t bucket;
-};
-
-struct tis_val_t {
-    uint64_t ar[FREQS_PER_ENTRY];
-};
-
-struct concurrent_val_t {
-    uint64_t active[CPUS_PER_ENTRY];
-    uint64_t policy[CPUS_PER_ENTRY];
-};
-
-struct freq_idx_key_t {
-    uint32_t policy;
-    uint32_t freq;
-};
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3f8b436..da51675 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -32,6 +32,8 @@
     defaults: ["libgui_bufferqueue-defaults"],
 
     srcs: [
+        ":libgui_bufferqueue_sources",
+
         "BitTube.cpp",
         "BufferHubConsumer.cpp",
         "BufferHubProducer.cpp",
@@ -104,32 +106,14 @@
     ],
 
     defaults: ["libgui_bufferqueue-defaults"],
+
+    srcs: [
+        ":libgui_bufferqueue_sources",
+    ],
 }
 
-// Common build config shared by libgui and libgui_bufferqueue_static.
-cc_defaults {
-    name: "libgui_bufferqueue-defaults",
-
-    clang: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    cppflags: [
-        "-Wextra",
-        "-DDEBUG_ONLY_CODE=0",
-    ],
-
-    product_variables: {
-        eng: {
-            cppflags: [
-                "-UDEBUG_ONLY_CODE",
-                "-DDEBUG_ONLY_CODE=1",
-            ],
-        },
-    },
-
+filegroup {
+    name: "libgui_bufferqueue_sources",
     srcs: [
         "BufferItem.cpp",
         "BufferQueue.cpp",
@@ -157,6 +141,31 @@
         "bufferqueue/2.0/H2BProducerListener.cpp",
         "bufferqueue/2.0/types.cpp",
     ],
+}
+
+// Common build config shared by libgui and libgui_bufferqueue_static.
+cc_defaults {
+    name: "libgui_bufferqueue-defaults",
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    cppflags: [
+        "-Wextra",
+        "-DDEBUG_ONLY_CODE=0",
+    ],
+
+    product_variables: {
+        eng: {
+            cppflags: [
+                "-UDEBUG_ONLY_CODE",
+                "-DDEBUG_ONLY_CODE=1",
+            ],
+        },
+    },
 
     shared_libs: [
         "android.hardware.graphics.bufferqueue@1.0",
@@ -204,4 +213,21 @@
     ],
 }
 
+// GMocks for use by external code
+cc_library_static {
+    name: "libgui_mocks",
+    vendor_available: false,
+
+    defaults: ["libgui_bufferqueue-defaults"],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+
+    srcs: [
+        "mock/GraphicBufferConsumer.cpp",
+        "mock/GraphicBufferProducer.cpp",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 129558b..b98e48b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -34,7 +34,8 @@
     CREATE_WITH_SURFACE_PARENT,
     CLEAR_LAYER_FRAME_STATS,
     GET_LAYER_FRAME_STATS,
-    LAST = GET_LAYER_FRAME_STATS,
+    MIRROR_SURFACE,
+    LAST = MIRROR_SURFACE,
 };
 
 } // Anonymous namespace
@@ -80,6 +81,12 @@
                 &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle,
                                                               outStats);
     }
+
+    status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) override {
+        return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE,
+                                                                            mirrorFromHandle,
+                                                                            outHandle);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -105,6 +112,8 @@
             return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
         case Tag::GET_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
+        case Tag::MIRROR_SURFACE:
+            return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface);
     }
 }
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index fb9d742..e490d6d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1087,6 +1087,12 @@
     case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT:
         res = dispatchSetDequeueTimeout(args);
         break;
+    case NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION:
+        res = dispatchGetLastDequeueDuration(args);
+        break;
+    case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION:
+        res = dispatchGetLastQueueDuration(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1303,6 +1309,18 @@
     return setDequeueTimeout(timeout);
 }
 
+int Surface::dispatchGetLastDequeueDuration(va_list args) {
+    int64_t* lastDequeueDuration = va_arg(args, int64_t*);
+    *lastDequeueDuration = mLastDequeueDuration;
+    return NO_ERROR;
+}
+
+int Surface::dispatchGetLastQueueDuration(va_list args) {
+    int64_t* lastQueueDuration = va_arg(args, int64_t*);
+    *lastQueueDuration = mLastQueueDuration;
+    return NO_ERROR;
+}
+
 bool Surface::transformToDisplayInverse() {
     return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6b5021d..7b256f5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1327,7 +1327,9 @@
             break;
     }
     setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]);
-    setPosition(sc, x, y);
+    float offsetX = xScale * source.left;
+    float offsetY = yScale * source.top;
+    setPosition(sc, x - offsetX, y - offsetY);
 
     return *this;
 }
@@ -1503,6 +1505,20 @@
     return err;
 }
 
+sp<SurfaceControl> SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFromSurface) {
+    if (mirrorFromSurface == nullptr) {
+        return nullptr;
+    }
+
+    sp<IBinder> handle;
+    sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle();
+    status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle);
+    if (err == NO_ERROR) {
+        return new SurfaceControl(this, handle, nullptr, true /* owned */);
+    }
+    return nullptr;
+}
+
 status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
     if (mStatus != NO_ERROR) {
         return mStatus;
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 32ac9e8..5fe7ca5 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -76,6 +76,8 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
+
+    virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) = 0;
 };
 
 class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 2527ec0..e582509 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -246,6 +246,8 @@
     int dispatchSetAutoPrerotation(va_list args);
     int dispatchGetLastDequeueStartTime(va_list args);
     int dispatchSetDequeueTimeout(va_list args);
+    int dispatchGetLastDequeueDuration(va_list args);
+    int dispatchGetLastQueueDuration(va_list args);
     bool transformToDisplayInverse();
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 15287e2..6676be4 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -245,6 +245,17 @@
                                                LayerMetadata metadata = LayerMetadata() // metadata
     );
 
+    // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl
+    // which is a parent of the root of the mirrored hierarchy.
+    //
+    //  Real Hierarchy    Mirror
+    //                      SC (value that's returned)
+    //                      |
+    //      A               A'
+    //      |               |
+    //      B               B'
+    sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface);
+
     //! Create a virtual display
     static sp<IBinder> createDisplay(const String8& displayName, bool secure);
 
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
similarity index 100%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
rename to libs/gui/include/gui/mock/GraphicBufferConsumer.h
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h b/libs/gui/include/gui/mock/GraphicBufferProducer.h
similarity index 100%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
rename to libs/gui/include/gui/mock/GraphicBufferProducer.h
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp b/libs/gui/mock/GraphicBufferConsumer.cpp
similarity index 94%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
rename to libs/gui/mock/GraphicBufferConsumer.cpp
index a17b73f..4a6c081 100644
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
+++ b/libs/gui/mock/GraphicBufferConsumer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "mock/gui/MockGraphicBufferConsumer.h"
+#include <gui/mock/GraphicBufferConsumer.h>
 
 namespace android {
 namespace mock {
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp b/libs/gui/mock/GraphicBufferProducer.cpp
similarity index 94%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
rename to libs/gui/mock/GraphicBufferProducer.cpp
index a7fd667..239a80a 100644
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
+++ b/libs/gui/mock/GraphicBufferProducer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "mock/gui/MockGraphicBufferProducer.h"
+#include <gui/mock/GraphicBufferProducer.h>
 
 namespace android {
 namespace mock {
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index fecfa19..0ba01f4 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -33,6 +33,12 @@
     return res < 0 ? res : value;
 }
 
+static int64_t query64(ANativeWindow* window, int what) {
+    int64_t value;
+    int res = window->perform(window, what, &value);
+    return res < 0 ? res : value;
+}
+
 static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) {
     bool supported = false;
     switch (dataSpace) {
@@ -271,18 +277,16 @@
  * apex-stable
  **************************************************************************************************/
 
-int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) {
-    return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION);
+int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window) {
+    return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION);
 }
 
-int ANativeWindow_getLastQueueDuration(ANativeWindow* window) {
-    return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION);
+int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window) {
+    return query64(window, NATIVE_WINDOW_GET_LAST_QUEUE_DURATION);
 }
 
 int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) {
-    int64_t time;
-    int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time);
-    return success < 0 ? success : time;
+    return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START);
 }
 
 int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) {
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 9798c2f..869b22e 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -27,17 +27,17 @@
  * Retrieves how long it took for the last time a buffer was dequeued.
  *
  * \return a negative value on error, otherwise returns the duration in
- * microseconds.
+ * nanoseconds
  */
-int ANativeWindow_getLastDequeueDuration(ANativeWindow* window);
+int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window);
 
 /**
  * Retrieves how long it took for the last time a buffer was queued.
  *
  * \return a negative value on error, otherwise returns the duration in
- * microseconds
+ * nanoseconds.
  */
-int ANativeWindow_getLastQueueDuration(ANativeWindow* window);
+int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window);
 
 /**
  * Retrieves the system time in nanoseconds when the last time a buffer
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 8f85007..1814ab5 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -63,9 +63,9 @@
 
 /* attributes queriable with query() */
 enum {
-    NATIVE_WINDOW_WIDTH     = 0,
-    NATIVE_WINDOW_HEIGHT    = 1,
-    NATIVE_WINDOW_FORMAT    = 2,
+    NATIVE_WINDOW_WIDTH = 0,
+    NATIVE_WINDOW_HEIGHT = 1,
+    NATIVE_WINDOW_FORMAT = 2,
 
     /* see ANativeWindowQuery in vndk/window.h */
     NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS,
@@ -147,11 +147,15 @@
 
     /*
      * Returns the duration of the last dequeueBuffer call in microseconds
+     * Deprecated: please use NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION in
+     * perform() instead, which supports nanosecond precision.
      */
     NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
 
     /*
      * Returns the duration of the last queueBuffer call in microseconds
+     * Deprecated: please use NATIVE_WINDOW_GET_LAST_QUEUE_DURATION in
+     * perform() instead, which supports nanosecond precision.
      */
     NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
 
@@ -241,6 +245,8 @@
     NATIVE_WINDOW_SET_AUTO_PREROTATION            = 35,
     NATIVE_WINDOW_GET_LAST_DEQUEUE_START          = 36,    /* private */
     NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT             = 37,    /* private */
+    NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION       = 38,    /* private */
+    NATIVE_WINDOW_GET_LAST_QUEUE_DURATION         = 39,    /* private */
     // clang-format on
 };
 
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
index 4d2b8c8..6cf8291 100644
--- a/libs/nativewindow/tests/ANativeWindowTest.cpp
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -74,7 +74,7 @@
 TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) {
     int result = ANativeWindow_getLastDequeueDuration(mWindow.get());
     EXPECT_EQ(0, result);
-    EXPECT_EQ(0, mWindow->getLastDequeueDuration() / 1000);
+    EXPECT_EQ(0, mWindow->getLastDequeueDuration());
 }
 
 TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) {
@@ -86,7 +86,7 @@
 
     result = ANativeWindow_getLastDequeueDuration(mWindow.get());
     EXPECT_GT(result, 0);
-    EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000);
+    EXPECT_EQ(result, mWindow->getLastDequeueDuration());
 }
 
 TEST_F(ANativeWindowTest, getLastQueueDuration_noDequeue_returnsZero) {
@@ -118,7 +118,7 @@
 
     result = ANativeWindow_getLastQueueDuration(mWindow.get());
     EXPECT_GT(result, 0);
-    EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000);
+    EXPECT_EQ(result, mWindow->getLastQueueDuration());
 }
 
 TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index f39f066..b8cf0ea 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -457,8 +457,10 @@
 }
 
 void GLESRenderEngine::primeCache() const {
-    ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
-                                           mFeatureFlags & USE_COLOR_MANAGEMENT);
+    ProgramCache::getInstance().primeCache(
+            mInProtectedContext ? mProtectedEGLContext : mEGLContext,
+                    mFeatureFlags & USE_COLOR_MANAGEMENT,
+                    mFeatureFlags & PRECACHE_TONE_MAPPER_SHADER_ONLY);
 }
 
 base::unique_fd GLESRenderEngine::flush() {
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index d242677..494623e 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -77,9 +77,38 @@
     return f;
 }
 
-void ProgramCache::primeCache(EGLContext context, bool useColorManagement) {
+void ProgramCache::primeCache(
+        EGLContext context, bool useColorManagement, bool toneMapperShaderOnly) {
     auto& cache = mCaches[context];
     uint32_t shaderCount = 0;
+
+    if (toneMapperShaderOnly) {
+        Key shaderKey;
+        // base settings used by HDR->SDR tonemap only
+        shaderKey.set(Key::BLEND_MASK | Key::INPUT_TRANSFORM_MATRIX_MASK |
+                      Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::OUTPUT_TF_MASK |
+                      Key::OPACITY_MASK | Key::ALPHA_MASK |
+                      Key::ROUNDED_CORNERS_MASK | Key::TEXTURE_MASK,
+                      Key::BLEND_NORMAL | Key::INPUT_TRANSFORM_MATRIX_ON |
+                      Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::OUTPUT_TF_SRGB |
+                      Key::OPACITY_OPAQUE | Key::ALPHA_EQ_ONE |
+                      Key::ROUNDED_CORNERS_OFF | Key::TEXTURE_EXT);
+        for (int i = 0; i < 4; i++) {
+            // Cache input transfer for HLG & ST2084
+            shaderKey.set(Key::INPUT_TF_MASK, (i & 1) ?
+                    Key::INPUT_TF_HLG : Key::INPUT_TF_ST2084);
+
+            // Cache Y410 input on or off
+            shaderKey.set(Key::Y410_BT2020_MASK, (i & 2) ?
+                    Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
+            if (cache.count(shaderKey) == 0) {
+                cache.emplace(shaderKey, generateProgram(shaderKey));
+                shaderCount++;
+            }
+        }
+        return;
+    }
+
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK
         | Key::ROUNDED_CORNERS_MASK;
     // Prime the cache for all combinations of the above masks,
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 400ad74..175c6e8 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -179,7 +179,7 @@
     ~ProgramCache() = default;
 
     // Generate shaders to populate the cache
-    void primeCache(const EGLContext context, bool useColorManagement);
+    void primeCache(const EGLContext context, bool useColorManagement, bool toneMapperShaderOnly);
 
     size_t getSize(const EGLContext context) { return mCaches[context].size(); }
 
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 205782b..9dcd510 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -66,6 +66,9 @@
 
         // Create a protected context when if possible
         ENABLE_PROTECTED_CONTEXT = 1 << 2,
+
+        // Only precache HDR to SDR tone-mapping shaders
+        PRECACHE_TONE_MAPPER_SHADER_ONLY = 1 << 3,
     };
 
     static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 139987e..abc9103 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -577,7 +577,8 @@
     uint32_t len = static_cast<uint32_t>(string8.length());
     FlattenableUtils::write(buffer, size, len);
     memcpy(static_cast<char*>(buffer), string8.string(), len);
-    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+    FlattenableUtils::advance(buffer, size, len);
+    size -= FlattenableUtils::align<4>(buffer);
 }
 
 bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) {
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 2053344..04493f0 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -40,6 +40,7 @@
     "android.hardware.graphics.composer@2.1",
     "android.hardware.graphics.composer@2.2",
     "android.hardware.graphics.composer@2.3",
+    "android.hardware.graphics.composer@2.4",
     "libbinder",
     "libbase",
     "libbufferhubqueue",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index aa51e23..4db9ae2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2772,7 +2772,7 @@
           "yCursorPosition=%f, downTime=%" PRId64,
           args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
           args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
-          args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition,
+          args->edgeFlags, args->xPrecision, args->yPrecision, args->xCursorPosition,
           args->yCursorPosition, args->downTime);
     for (uint32_t i = 0; i < args->pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index a64f4dd..3c16070 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -50,6 +50,7 @@
 
     shared_libs: [
         "libbase",
+        "libcap",
         "libinputflinger_base",
         "libcrypto",
         "libcutils",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index efe3809..c8da0ab 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <sys/epoll.h>
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
@@ -237,6 +238,47 @@
     return !isVirtual && enabled;
 }
 
+/**
+ * Get the capabilities for the current process.
+ * Crashes the system if unable to create / check / destroy the capabilities object.
+ */
+class Capabilities final {
+public:
+    explicit Capabilities() {
+        mCaps = cap_get_proc();
+        LOG_ALWAYS_FATAL_IF(mCaps == nullptr, "Could not get capabilities of the current process");
+    }
+
+    /**
+     * Check whether the current process has a specific capability
+     * in the set of effective capabilities.
+     * Return CAP_SET if the process has the requested capability
+     * Return CAP_CLEAR otherwise.
+     */
+    cap_flag_value_t checkEffectiveCapability(cap_value_t capability) {
+        cap_flag_value_t value;
+        const int result = cap_get_flag(mCaps, capability, CAP_EFFECTIVE, &value);
+        LOG_ALWAYS_FATAL_IF(result == -1, "Could not obtain the requested capability");
+        return value;
+    }
+
+    ~Capabilities() {
+        const int result = cap_free(mCaps);
+        LOG_ALWAYS_FATAL_IF(result == -1, "Could not release the capabilities structure");
+    }
+
+private:
+    cap_t mCaps;
+};
+
+static void ensureProcessCanBlockSuspend() {
+    Capabilities capabilities;
+    const bool canBlockSuspend =
+            capabilities.checkEffectiveCapability(CAP_BLOCK_SUSPEND) == CAP_SET;
+    LOG_ALWAYS_FATAL_IF(!canBlockSuspend,
+                        "Input must be able to block suspend to properly process events");
+}
+
 // --- EventHub ---
 
 const int EventHub::EPOLL_MAX_EVENTS;
@@ -253,6 +295,7 @@
         mPendingEventCount(0),
         mPendingEventIndex(0),
         mPendingINotify(false) {
+    ensureProcessCanBlockSuspend();
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 
     mEpollFd = epoll_create1(EPOLL_CLOEXEC);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index b404836..e5d23d0 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -29,6 +29,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
         "libbase",
@@ -92,6 +93,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.3",
         "libhidlbase",
     ],
@@ -166,6 +168,7 @@
         "Scheduler/VSyncModulator.cpp",
         "StartPropertySetThread.cpp",
         "SurfaceFlinger.cpp",
+        "SurfaceFlingerDefaultFactory.cpp",
         "SurfaceInterceptor.cpp",
         "SurfaceTracing.cpp",
         "TransactionCompletedThread.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d189846..b500ad3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -295,7 +295,7 @@
                                     const CompositorTiming& compositorTiming) {
     // mFrameLatencyNeeded is true when a new frame was latched for the
     // composition.
-    if (!mFrameLatencyNeeded) return false;
+    if (!mBufferInfo.mFrameLatencyNeeded) return false;
 
     // Update mFrameEventHistory.
     {
@@ -337,7 +337,7 @@
     }
 
     mFrameTracker.advanceFrame();
-    mFrameLatencyNeeded = false;
+    mBufferInfo.mFrameLatencyNeeded = false;
     return true;
 }
 
@@ -401,7 +401,7 @@
     gatherBufferInfo();
 
     mRefreshPending = true;
-    mFrameLatencyNeeded = true;
+    mBufferInfo.mFrameLatencyNeeded = true;
     if (oldBufferInfo.mBuffer == nullptr) {
         // the first time we receive a buffer, we need to trigger a
         // geometry invalidation.
@@ -735,6 +735,35 @@
     mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
     mPotentialCursor = bufferClonedFrom->mPotentialCursor;
     mProtectedByApp = bufferClonedFrom->mProtectedByApp;
+
+    updateCloneBufferInfo();
+}
+
+void BufferLayer::updateCloneBufferInfo() {
+    if (!isClone() || !isClonedFromAlive()) {
+        return;
+    }
+
+    sp<BufferLayer> clonedFrom = static_cast<BufferLayer*>(getClonedFrom().get());
+    mBufferInfo = clonedFrom->mBufferInfo;
+    mSidebandStream = clonedFrom->mSidebandStream;
+    surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
+    mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
+    mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
+
+    // After buffer info is updated, the drawingState from the real layer needs to be copied into
+    // the cloned. This is because some properties of drawingState can change when latchBuffer is
+    // called. However, copying the drawingState would also overwrite the cloned layer's relatives.
+    // Therefore, temporarily store the relatives so they can be set in the cloned drawingState
+    // again.
+    wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
+    SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
+    mDrawingState = clonedFrom->mDrawingState;
+    // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+    // InputWindows per client token yet.
+    mDrawingState.inputInfo.token = nullptr;
+    mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
+    mDrawingState.zOrderRelatives = tmpZOrderRelatives;
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b2c0618..656ba12 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -165,6 +165,8 @@
 
         sp<GraphicBuffer> mBuffer;
         int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+
+        bool mFrameLatencyNeeded{false};
     };
 
     BufferInfo mBufferInfo;
@@ -195,6 +197,8 @@
 
     ui::Dataspace translateDataspace(ui::Dataspace dataspace);
     void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+    void updateCloneBufferInfo() override;
+    uint64_t mPreviousFrameNumber = 0;
 
 private:
     // Returns true if this layer requires filtering
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index eb13f65..d80a70e 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -531,7 +531,7 @@
     LayerCreationArgs args =
             LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
     args.textureName = mTextureName;
-    sp<BufferQueueLayer> layer = new BufferQueueLayer(args);
+    sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args);
     layer->setInitialValuesForClone(this);
 
     return layer;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 36dff15..f3e8a19 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -111,8 +111,6 @@
 
     PixelFormat mFormat{PIXEL_FORMAT_NONE};
 
-    // Only accessed on the main thread.
-    uint64_t mPreviousFrameNumber{0};
     bool mUpdateTexImageFailed{false};
 
     uint64_t mPreviousBufferId = 0;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 30fdbe1..75fc0e9 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -125,9 +125,10 @@
 
 bool BufferStateLayer::willPresentCurrentTransaction() const {
     // Returns true if the most recent Transaction applied to CurrentState will be presented.
-    return getSidebandStreamChanged() || getAutoRefresh() ||
+    return (getSidebandStreamChanged() || getAutoRefresh() ||
             (mCurrentState.modified &&
-             (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr));
+             (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr))) &&
+        !mLayerDetached;
 }
 
 void BufferStateLayer::pushPendingState() {
@@ -672,7 +673,7 @@
     LayerCreationArgs args =
             LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
     args.textureName = mTextureName;
-    sp<BufferStateLayer> layer = new BufferStateLayer(args);
+    sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
     layer->mHwcSlotGenerator = mHwcSlotGenerator;
     layer->setInitialValuesForClone(this);
     return layer;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index e951ccf..3dfe76c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -143,7 +143,6 @@
 
     sp<Fence> mPreviousReleaseFence;
     uint64_t mPreviousBufferId = 0;
-    uint64_t mPreviousFrameNumber = 0;
     uint64_t mPreviousReleasedFrameNumber = 0;
 
     mutable bool mCurrentStateModified = false;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 6bfd302..c7ed9b0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -106,6 +106,10 @@
                                  nullptr, layer);
 }
 
+status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) {
+    return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle);
+}
+
 status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
     sp<Layer> layer = getLayerUser(handle);
     if (layer == nullptr) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 74e4818..7d7cef8 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -62,6 +62,8 @@
                                              LayerMetadata metadata, sp<IBinder>* handle,
                                              sp<IGraphicBufferProducer>* gbp);
 
+    status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle);
+
     virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
 
     virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 5b62054..172d445 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -109,7 +109,7 @@
 
 sp<Layer> ColorLayer::createClone() {
     String8 name = mName + " (Mirror)";
-    sp<ColorLayer> layer = new ColorLayer(
+    sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer(
             LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 1407ef7..738a2a4 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -11,6 +11,7 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
         "libbase",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 389b605..a9a95cd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -74,7 +74,7 @@
 
     // Recalculates the state of the output layer from the output-independent
     // layer. If includeGeometry is false, the geometry state can be skipped.
-    virtual void updateCompositionState(bool includeGeometry) = 0;
+    virtual void updateCompositionState(bool includeGeometry, bool forceClientComposition) = 0;
 
     // Writes the geometry state to the HWC, or does nothing if this layer does
     // not use the HWC. If includeGeometry is false, the geometry state can be
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 34dbfb7..95c8afb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -39,7 +39,7 @@
 
     void setHwcLayer(std::shared_ptr<HWC2::Layer>) override;
 
-    void updateCompositionState(bool) override;
+    void updateCompositionState(bool includeGeometry, bool forceClientComposition) override;
     void writeStateToHWC(bool) override;
     void writeCursorPositionToHWC() const override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 4f2afac..631760a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -40,7 +40,7 @@
     MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
     MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
 
-    MOCK_METHOD1(updateCompositionState, void(bool));
+    MOCK_METHOD2(updateCompositionState, void(bool, bool));
     MOCK_METHOD1(writeStateToHWC, void(bool));
     MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2007ea3..aa638b7 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -552,11 +552,8 @@
     ALOGV(__FUNCTION__);
 
     for (auto* layer : getOutputLayersOrderedByZ()) {
-        if (refreshArgs.devOptForceClientComposition) {
-            layer->editState().forceClientComposition = true;
-        }
-
-        layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame);
+        layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
+                                      refreshArgs.devOptForceClientComposition);
 
         // Send the updated state to the HWC, if appropriate.
         layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 0124e5b..721e953 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -259,7 +259,7 @@
     return transform.getOrientation();
 } // namespace impl
 
-void OutputLayer::updateCompositionState(bool includeGeometry) {
+void OutputLayer::updateCompositionState(bool includeGeometry, bool forceClientComposition) {
     const auto& layerFEState = getLayer().getFEState();
     const auto& outputState = getOutput().getState();
     const auto& profile = *getOutput().getDisplayColorProfile();
@@ -294,7 +294,8 @@
 
     // These are evaluated every frame as they can potentially change at any
     // time.
-    if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace)) {
+    if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
+        forceClientComposition) {
         state.forceClientComposition = true;
     }
 }
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0347f75..a338784 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -501,7 +501,7 @@
 
     setupGeometryChildCallValues();
 
-    mOutputLayer.updateCompositionState(true);
+    mOutputLayer.updateCompositionState(true, false);
 
     validateComputedGeometryState();
 
@@ -515,7 +515,7 @@
 
     setupGeometryChildCallValues();
 
-    mOutputLayer.updateCompositionState(true);
+    mOutputLayer.updateCompositionState(true, false);
 
     validateComputedGeometryState();
 
@@ -531,7 +531,7 @@
 
     setupGeometryChildCallValues();
 
-    mOutputLayer.updateCompositionState(true);
+    mOutputLayer.updateCompositionState(true, false);
 
     validateComputedGeometryState();
 
@@ -546,7 +546,7 @@
     // should use the layers requested colorspace.
     mLayerFEState.isColorspaceAgnostic = false;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
 
@@ -554,7 +554,7 @@
     // should use the colorspace chosen for the whole output.
     mLayerFEState.isColorspaceAgnostic = true;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
 }
@@ -562,7 +562,7 @@
 TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
     mOutputLayer.editState().forceClientComposition = false;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
 }
@@ -571,7 +571,7 @@
        doesNotClearForceClientCompositionIfNotDoingGeometry) {
     mOutputLayer.editState().forceClientComposition = true;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
 }
@@ -580,7 +580,7 @@
     mLayerFEState.forceClientComposition = true;
     mOutputLayer.editState().forceClientComposition = false;
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
 
     EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
 }
@@ -590,7 +590,24 @@
     mOutputLayer.editState().forceClientComposition = false;
     EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
 
-    mOutputLayer.updateCompositionState(false);
+    mOutputLayer.updateCompositionState(false, false);
+
+    EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromArgumentFlag) {
+    mLayerFEState.forceClientComposition = false;
+    mOutputLayer.editState().forceClientComposition = false;
+
+    mOutputLayer.updateCompositionState(false, true);
+
+    EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+
+    mOutputLayer.editState().forceClientComposition = false;
+
+    setupGeometryChildCallValues();
+
+    mOutputLayer.updateCompositionState(true, true);
 
     EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
 }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index cb50d9f..e58e6f4 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -32,7 +32,7 @@
 
 sp<Layer> ContainerLayer::createClone() {
     String8 name = mName + " (Mirror)";
-    sp<ContainerLayer> layer = new ContainerLayer(
+    sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer(
             LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
     layer->setInitialValuesForClone(this);
     return layer;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index e53d099..acddc42 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -17,9 +17,11 @@
 #undef LOG_TAG
 #define LOG_TAG "HwcComposer"
 
-#include <inttypes.h>
 #include <log/log.h>
 
+#include <algorithm>
+#include <cinttypes>
+
 #include "ComposerHal.h"
 
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
@@ -173,7 +175,16 @@
         LOG_ALWAYS_FATAL("failed to get hwcomposer service");
     }
 
-    if (sp<IComposer> composer_2_3 = IComposer::castFrom(mComposer)) {
+    if (sp<IComposer> composer_2_4 = IComposer::castFrom(mComposer)) {
+        composer_2_4->createClient_2_4([&](const auto& tmpError, const auto& tmpClient) {
+            if (tmpError == Error::NONE) {
+                mClient = tmpClient;
+                mClient_2_2 = tmpClient;
+                mClient_2_3 = tmpClient;
+                mClient_2_4 = tmpClient;
+            }
+        });
+    } else if (sp<V2_3::IComposer> composer_2_3 = V2_3::IComposer::castFrom(mComposer)) {
         composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) {
             if (tmpError == Error::NONE) {
                 mClient = tmpClient;
@@ -456,23 +467,6 @@
     return Error::NONE;
 }
 
-Error Composer::getDisplayType(Display display,
-        IComposerClient::DisplayType* outType)
-{
-    Error error = kDefaultError;
-    mClient->getDisplayType(display,
-            [&](const auto& tmpError, const auto& tmpType) {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
-
-                *outType = tmpType;
-            });
-
-    return error;
-}
-
 Error Composer::getDozeSupport(Display display, bool* outSupport)
 {
     Error error = kDefaultError;
@@ -1113,23 +1107,6 @@
     return error;
 }
 
-Error Composer::getDisplayCapabilities(Display display,
-                                       std::vector<DisplayCapability>* outCapabilities) {
-    if (!mClient_2_3) {
-        return Error::UNSUPPORTED;
-    }
-    Error error = kDefaultError;
-    mClient_2_3->getDisplayCapabilities(display,
-                                        [&](const auto& tmpError, const auto& tmpCapabilities) {
-                                            error = tmpError;
-                                            if (error != Error::NONE) {
-                                                return;
-                                            }
-                                            *outCapabilities = tmpCapabilities;
-                                        });
-    return error;
-}
-
 Error Composer::setDisplayContentSamplingEnabled(Display display, bool enabled,
                                                  uint8_t componentMask, uint64_t maxFrames) {
     if (!mClient_2_3) {
@@ -1187,6 +1164,60 @@
     return mClient_2_3->setDisplayBrightness(display, brightness);
 }
 
+// Composer HAL 2.4
+
+Error Composer::getDisplayCapabilities(Display display,
+                                       std::vector<DisplayCapability>* outCapabilities) {
+    if (!mClient_2_3) {
+        return Error::UNSUPPORTED;
+    }
+
+    Error error = kDefaultError;
+    if (mClient_2_4) {
+        mClient_2_4->getDisplayCapabilities_2_4(display,
+                                                [&](const auto& tmpError, const auto& tmpCaps) {
+                                                    error = tmpError;
+                                                    if (error != Error::NONE) {
+                                                        return;
+                                                    }
+                                                    *outCapabilities = tmpCaps;
+                                                });
+    } else {
+        mClient_2_3
+                ->getDisplayCapabilities(display, [&](const auto& tmpError, const auto& tmpCaps) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
+
+                    outCapabilities->resize(tmpCaps.size());
+                    std::transform(tmpCaps.begin(), tmpCaps.end(), outCapabilities->begin(),
+                                   [](auto cap) { return static_cast<DisplayCapability>(cap); });
+                });
+    }
+
+    return error;
+}
+
+Error Composer::getDisplayConnectionType(Display display,
+                                         IComposerClient::DisplayConnectionType* outType) {
+    if (!mClient_2_4) {
+        return Error::UNSUPPORTED;
+    }
+
+    Error error = kDefaultError;
+    mClient_2_4->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+
+        *outType = tmpType;
+    });
+
+    return error;
+}
+
 CommandReader::~CommandReader()
 {
     resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 9f6cac2..e743e59 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -27,8 +27,8 @@
 #include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
 #endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
 #include <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/composer/2.3/IComposer.h>
-#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
@@ -49,6 +49,7 @@
 namespace V2_1 = hardware::graphics::composer::V2_1;
 namespace V2_2 = hardware::graphics::composer::V2_2;
 namespace V2_3 = hardware::graphics::composer::V2_3;
+namespace V2_4 = hardware::graphics::composer::V2_4;
 
 using types::V1_0::ColorTransform;
 using types::V1_0::Transform;
@@ -65,8 +66,8 @@
 using V2_1::Layer;
 using V2_3::CommandReaderBase;
 using V2_3::CommandWriterBase;
-using V2_3::IComposer;
-using V2_3::IComposerClient;
+using V2_4::IComposer;
+using V2_4::IComposerClient;
 using DisplayCapability = IComposerClient::DisplayCapability;
 using PerFrameMetadata = IComposerClient::PerFrameMetadata;
 using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
@@ -118,7 +119,6 @@
                                      std::vector<Layer>* outLayers,
                                      std::vector<uint32_t>* outLayerRequestMasks) = 0;
 
-    virtual Error getDisplayType(Display display, IComposerClient::DisplayType* outType) = 0;
     virtual Error getDozeSupport(Display display, bool* outSupport) = 0;
     virtual Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes,
                                      float* outMaxLuminance, float* outMaxAverageLuminance,
@@ -203,11 +203,15 @@
                                                    uint8_t componentMask, uint64_t maxFrames) = 0;
     virtual Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
                                             DisplayedFrameStats* outStats) = 0;
-    virtual Error getDisplayCapabilities(Display display,
-                                         std::vector<DisplayCapability>* outCapabilities) = 0;
     virtual Error setLayerPerFrameMetadataBlobs(
             Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0;
     virtual Error setDisplayBrightness(Display display, float brightness) = 0;
+
+    // Composer HAL 2.4
+    virtual Error getDisplayCapabilities(Display display,
+                                         std::vector<DisplayCapability>* outCapabilities) = 0;
+    virtual Error getDisplayConnectionType(Display display,
+                                           IComposerClient::DisplayConnectionType* outType) = 0;
 };
 
 namespace impl {
@@ -334,7 +338,6 @@
                              std::vector<Layer>* outLayers,
                              std::vector<uint32_t>* outLayerRequestMasks) override;
 
-    Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
     Error getDozeSupport(Display display, bool* outSupport) override;
     Error getHdrCapabilities(Display display, std::vector<Hdr>* outTypes, float* outMaxLuminance,
                              float* outMaxAverageLuminance, float* outMinLuminance) override;
@@ -414,13 +417,17 @@
                                            uint64_t maxFrames) override;
     Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
                                     DisplayedFrameStats* outStats) override;
-    Error getDisplayCapabilities(Display display,
-                                 std::vector<DisplayCapability>* outCapabilities) override;
     Error setLayerPerFrameMetadataBlobs(
             Display display, Layer layer,
             const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
     Error setDisplayBrightness(Display display, float brightness) override;
 
+    // Composer HAL 2.4
+    Error getDisplayCapabilities(Display display,
+                                 std::vector<DisplayCapability>* outCapabilities) override;
+    Error getDisplayConnectionType(Display display,
+                                   IComposerClient::DisplayConnectionType* outType) override;
+
 private:
 #if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
     class CommandWriter : public CommandWriterBase {
@@ -455,7 +462,8 @@
 
     sp<V2_1::IComposerClient> mClient;
     sp<V2_2::IComposerClient> mClient_2_2;
-    sp<IComposerClient> mClient_2_3;
+    sp<V2_3::IComposerClient> mClient_2_3;
+    sp<IComposerClient> mClient_2_4;
 
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize =
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c463c4e..6f7428a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -169,20 +169,8 @@
         }
         mDisplays.erase(displayId);
 
-        DisplayType displayType;
-        auto intError = mComposer->getDisplayType(displayId,
-                reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(
-                        &displayType));
-        auto error = static_cast<Error>(intError);
-        if (error != Error::None) {
-            ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d). "
-                    "Aborting hotplug attempt.",
-                    displayId, to_string(error).c_str(), intError);
-            return;
-        }
-
         auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities,
-                                                          displayId, displayType);
+                                                          displayId, DisplayType::Physical);
         newDisplay->setConnected(true);
         mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 079bc66..6a45625 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -780,6 +780,15 @@
     ATRACE_CALL();
 
     if (mLayerDetached) {
+        // Ensure BLAST buffer callbacks are processed.
+        // detachChildren and mLayerDetached were implemented to avoid geometry updates
+        // to layers in the cases of animation. For BufferQueue layers buffers are still
+        // consumed as normal. This is useful as otherwise the client could get hung
+        // inevitably waiting on a buffer to return. We recreate this semantic for BufferQueue
+        // even though it is a little consistent. detachChildren is shortly slated for removal
+        // by the hierarchy mirroring work so we don't need to worry about it too much.
+        mDrawingState.callbackHandles = mCurrentState.callbackHandles;
+        mCurrentState.callbackHandles = {};
         return flags;
     }
 
@@ -2025,6 +2034,118 @@
     // InputWindows per client token yet.
     mDrawingState.inputInfo.token = nullptr;
 }
+
+void Layer::updateMirrorInfo() {
+    if (mClonedChild == nullptr || !mClonedChild->isClonedFromAlive()) {
+        // If mClonedChild is null, there is nothing to mirror. If isClonedFromAlive returns false,
+        // it means that there is a clone, but the layer it was cloned from has been destroyed. In
+        // that case, we want to delete the reference to the clone since we want it to get
+        // destroyed. The root, this layer, will still be around since the client can continue
+        // to hold a reference, but no cloned layers will be displayed.
+        mClonedChild = nullptr;
+        return;
+    }
+
+    std::map<sp<Layer>, sp<Layer>> clonedLayersMap;
+    // If the real layer exists and is in current state, add the clone as a child of the root.
+    // There's no need to remove from drawingState when the layer is offscreen since currentState is
+    // copied to drawingState for the root layer. So the clonedChild is always removed from
+    // drawingState and then needs to be added back each traversal.
+    if (!mClonedChild->getClonedFrom()->isRemovedFromCurrentState()) {
+        addChildToDrawing(mClonedChild);
+    }
+
+    mClonedChild->updateClonedDrawingState(clonedLayersMap);
+    mClonedChild->updateClonedChildren(this, clonedLayersMap);
+    mClonedChild->updateClonedRelatives(clonedLayersMap);
+}
+
+void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+    // If the layer the clone was cloned from is alive, copy the content of the drawingState
+    // to the clone. If the real layer is no longer alive, continue traversing the children
+    // since we may be able to pull out other children that are still alive.
+    if (isClonedFromAlive()) {
+        sp<Layer> clonedFrom = getClonedFrom();
+        mDrawingState = clonedFrom->mDrawingState;
+        // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+        // InputWindows per client token yet.
+        mDrawingState.inputInfo.token = nullptr;
+        clonedLayersMap.emplace(clonedFrom, this);
+    }
+
+    // The clone layer may have children in drawingState since they may have been created and
+    // added from a previous request to updateMirorInfo. This is to ensure we don't recreate clones
+    // that already exist, since we can just re-use them.
+    // The drawingChildren will not get overwritten by the currentChildren since the clones are
+    // not updated in the regular traversal. They are skipped since the root will lose the
+    // reference to them when it copies its currentChildren to drawing.
+    for (sp<Layer>& child : mDrawingChildren) {
+        child->updateClonedDrawingState(clonedLayersMap);
+    }
+}
+
+void Layer::updateClonedChildren(const sp<Layer>& mirrorRoot,
+                                 std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+    mDrawingChildren.clear();
+
+    if (!isClonedFromAlive()) {
+        return;
+    }
+
+    sp<Layer> clonedFrom = getClonedFrom();
+    for (sp<Layer>& child : clonedFrom->mDrawingChildren) {
+        if (child == mirrorRoot) {
+            // This is to avoid cyclical mirroring.
+            continue;
+        }
+        sp<Layer> clonedChild = clonedLayersMap[child];
+        if (clonedChild == nullptr) {
+            clonedChild = child->createClone();
+            clonedLayersMap[child] = clonedChild;
+        }
+        addChildToDrawing(clonedChild);
+        clonedChild->updateClonedChildren(mirrorRoot, clonedLayersMap);
+    }
+}
+
+void Layer::updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap) {
+    mDrawingState.zOrderRelativeOf = nullptr;
+    mDrawingState.zOrderRelatives.clear();
+
+    if (!isClonedFromAlive()) {
+        return;
+    }
+
+    sp<Layer> clonedFrom = getClonedFrom();
+    for (wp<Layer>& relativeWeak : clonedFrom->mDrawingState.zOrderRelatives) {
+        sp<Layer> relative = relativeWeak.promote();
+        auto clonedRelative = clonedLayersMap[relative];
+        if (clonedRelative != nullptr) {
+            mDrawingState.zOrderRelatives.add(clonedRelative);
+        }
+    }
+
+    // Check if the relativeLayer for the real layer is part of the cloned hierarchy.
+    // It's possible that the layer it's relative to is outside the requested cloned hierarchy.
+    // In that case, we treat the layer as if the relativeOf has been removed. This way, it will
+    // still traverse the children, but the layer with the missing relativeOf will not be shown
+    // on screen.
+    sp<Layer> relativeOf = clonedFrom->mDrawingState.zOrderRelativeOf.promote();
+    sp<Layer> clonedRelativeOf = clonedLayersMap[relativeOf];
+    if (clonedRelativeOf != nullptr) {
+        mDrawingState.zOrderRelativeOf = clonedRelativeOf;
+    }
+
+    for (sp<Layer>& child : mDrawingChildren) {
+        child->updateClonedRelatives(clonedLayersMap);
+    }
+}
+
+void Layer::addChildToDrawing(const sp<Layer>& layer) {
+    mDrawingChildren.add(layer);
+    layer->mDrawingParent = this;
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 610df25..3023cf5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -468,13 +468,30 @@
     virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
     virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
 
-protected:
-    virtual sp<Layer> createClone() = 0;
-    sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
+    // This layer is not a clone, but it's the parent to the cloned hierarchy. The
+    // variable mClonedChild represents the top layer that will be cloned so this
+    // layer will be the parent of mClonedChild.
+    // The layers in the cloned hierarchy will match the lifetime of the real layers. That is
+    // if the real layer is destroyed, then the clone layer will also be destroyed.
+    sp<Layer> mClonedChild;
 
-    bool isClone() { return getClonedFrom() != nullptr; }
+    virtual sp<Layer> createClone() = 0;
+    void updateMirrorInfo();
+    virtual void updateCloneBufferInfo(){};
+
+protected:
+    sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
+    bool isClone() { return mClonedFrom != nullptr; }
+    bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
+
     virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
 
+    void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+    void updateClonedChildren(const sp<Layer>& mirrorRoot,
+                              std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+    void updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap);
+    void addChildToDrawing(const sp<Layer>& layer);
+
 public:
     /*
      * compositionengine::LayerFE overrides
@@ -838,7 +855,6 @@
     // We encode unset as -1.
     int32_t mOverrideScalingMode{-1};
     std::atomic<uint64_t> mCurrentFrameNumber{0};
-    bool mFrameLatencyNeeded{false};
     // Whether filtering is needed b/c of the drawingstate
     bool mNeedsFiltering{false};
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8699747..54e2065 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -258,7 +258,8 @@
         mFrameTracer(std::make_unique<FrameTracer>()),
         mEventQueue(mFactory.createMessageQueue()),
         mCompositionEngine(mFactory.createCompositionEngine()),
-        mPhaseOffsets(mFactory.createPhaseOffsets()) {}
+        mPhaseOffsets(mFactory.createPhaseOffsets()),
+        mPendingSyncInputWindows(false) {}
 
 SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
     ALOGI("SurfaceFlinger is starting");
@@ -876,7 +877,16 @@
         return BAD_VALUE;
     }
 
-    return display->getActiveConfig();
+    if (display->isPrimary()) {
+        std::lock_guard<std::mutex> lock(mActiveConfigLock);
+        if (mDesiredActiveConfigChanged) {
+            return mDesiredActiveConfig.configId;
+        } else {
+            return display->getActiveConfig();
+        }
+    } else {
+        return display->getActiveConfig();
+    }
 }
 
 void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
@@ -2600,6 +2610,7 @@
     });
 
     commitOffscreenLayers();
+    mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateMirrorInfo(); });
 }
 
 void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) {
@@ -2718,6 +2729,8 @@
         mBootStage = BootStage::BOOTANIMATION;
     }
 
+    mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+
     // Only continue with the refresh if there is actually new work to do
     return !mLayersWithQueuedFrames.empty() && newDataLatched;
 }
@@ -3385,6 +3398,35 @@
     return flags;
 }
 
+status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+                                     sp<IBinder>* outHandle) {
+    if (!mirrorFromHandle) {
+        return NAME_NOT_FOUND;
+    }
+
+    sp<Layer> mirrorLayer;
+    sp<Layer> mirrorFrom;
+    String8 uniqueName = getUniqueLayerName(String8("MirrorRoot"));
+
+    {
+        Mutex::Autolock _l(mStateLock);
+        mirrorFrom = fromHandle(mirrorFromHandle);
+        if (!mirrorFrom) {
+            return NAME_NOT_FOUND;
+        }
+
+        status_t result = createContainerLayer(client, uniqueName, -1, -1, 0, LayerMetadata(),
+                                               outHandle, &mirrorLayer);
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        mirrorLayer->mClonedChild = mirrorFrom->createClone();
+    }
+
+    return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false);
+}
+
 status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
                                      uint32_t h, PixelFormat format, uint32_t flags,
                                      LayerMetadata metadata, sp<IBinder>* handle,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2ea8f78..9f3a914 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -338,6 +338,7 @@
 
     // For unit tests
     friend class TestableSurfaceFlinger;
+    friend class TransactionApplicationTest;
 
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
@@ -623,6 +624,9 @@
                                   uint32_t h, uint32_t flags, LayerMetadata metadata,
                                   sp<IBinder>* outHandle, sp<Layer>* outLayer);
 
+    status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+                         sp<IBinder>* outHandle);
+
     String8 getUniqueLayerName(const String8& name);
 
     // called when all clients have released all their references to
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
new file mode 100644
index 0000000..f0457e3
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2019 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 <compositionengine/impl/CompositionEngine.h>
+#include <ui/GraphicBuffer.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "NativeWindowSurface.h"
+#include "StartPropertySetThread.h"
+#include "SurfaceFlingerDefaultFactory.h"
+#include "SurfaceInterceptor.h"
+
+#include "DisplayHardware/ComposerHal.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
+#include "Scheduler/Scheduler.h"
+
+namespace android::surfaceflinger {
+
+DefaultFactory::~DefaultFactory() = default;
+
+std::unique_ptr<DispSync> DefaultFactory::createDispSync(const char* name, bool hasSyncFramework) {
+    return std::make_unique<android::impl::DispSync>(name, hasSyncFramework);
+}
+
+std::unique_ptr<EventControlThread> DefaultFactory::createEventControlThread(
+        SetVSyncEnabled setVSyncEnabled) {
+    return std::make_unique<android::impl::EventControlThread>(std::move(setVSyncEnabled));
+}
+
+std::unique_ptr<HWComposer> DefaultFactory::createHWComposer(const std::string& serviceName) {
+    return std::make_unique<android::impl::HWComposer>(
+            std::make_unique<Hwc2::impl::Composer>(serviceName));
+}
+
+std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue() {
+    return std::make_unique<android::impl::MessageQueue>();
+}
+
+std::unique_ptr<scheduler::PhaseOffsets> DefaultFactory::createPhaseOffsets() {
+    return std::make_unique<scheduler::impl::PhaseOffsets>();
+}
+
+std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
+        SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs) {
+    return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs);
+}
+
+std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
+        SurfaceFlinger* flinger) {
+    return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+}
+
+sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
+        bool timestampPropertyValue) {
+    return new StartPropertySetThread(timestampPropertyValue);
+}
+
+sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) {
+    return new DisplayDevice(std::move(creationArgs));
+}
+
+sp<GraphicBuffer> DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height,
+                                                      PixelFormat format, uint32_t layerCount,
+                                                      uint64_t usage, std::string requestorName) {
+    return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+}
+
+void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                                       sp<IGraphicBufferConsumer>* outConsumer,
+                                       bool consumerIsSurfaceFlinger) {
+    BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+}
+
+std::unique_ptr<surfaceflinger::NativeWindowSurface> DefaultFactory::createNativeWindowSurface(
+        const sp<IGraphicBufferProducer>& producer) {
+    return surfaceflinger::impl::createNativeWindowSurface(producer);
+}
+
+std::unique_ptr<compositionengine::CompositionEngine> DefaultFactory::createCompositionEngine() {
+    return compositionengine::impl::createCompositionEngine();
+}
+
+sp<ContainerLayer> DefaultFactory::createContainerLayer(const LayerCreationArgs& args) {
+    return new ContainerLayer(args);
+}
+
+sp<BufferQueueLayer> DefaultFactory::createBufferQueueLayer(const LayerCreationArgs& args) {
+    return new BufferQueueLayer(args);
+}
+
+sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) {
+    return new BufferStateLayer(args);
+}
+
+sp<ColorLayer> DefaultFactory::createColorLayer(const LayerCreationArgs& args) {
+    return new ColorLayer(args);
+}
+
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
new file mode 100644
index 0000000..89e0679
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SurfaceFlingerFactory.h"
+
+namespace android::surfaceflinger {
+
+// A default implementation of the factory which creates the standard
+// implementation types for each interface.
+class DefaultFactory : public surfaceflinger::Factory {
+public:
+    virtual ~DefaultFactory();
+
+    std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override;
+    std::unique_ptr<EventControlThread> createEventControlThread(SetVSyncEnabled) override;
+    std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
+    std::unique_ptr<MessageQueue> createMessageQueue() override;
+    std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override;
+    std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
+                                               const scheduler::RefreshRateConfigs&) override;
+    std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
+    sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
+    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&&) override;
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+                                          uint32_t layerCount, uint64_t usage,
+                                          std::string requestorName) override;
+    void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
+                           sp<IGraphicBufferConsumer>* outConsumer,
+                           bool consumerIsSurfaceFlinger) override;
+    std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+            const sp<IGraphicBufferProducer>&) override;
+    std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
+    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override;
+    sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
+    sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override;
+    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
+};
+
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 4ddc132..9b1f658 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,116 +14,13 @@
  * limitations under the License.
  */
 
-#include <compositionengine/impl/CompositionEngine.h>
-#include <ui/GraphicBuffer.h>
-
-#include "BufferQueueLayer.h"
-#include "BufferStateLayer.h"
-#include "ColorLayer.h"
-#include "ContainerLayer.h"
-#include "DisplayDevice.h"
-#include "Layer.h"
-#include "NativeWindowSurface.h"
-#include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerFactory.h"
-#include "SurfaceInterceptor.h"
-
-#include "DisplayHardware/ComposerHal.h"
-#include "Scheduler/DispSync.h"
-#include "Scheduler/EventControlThread.h"
-#include "Scheduler/MessageQueue.h"
-#include "Scheduler/PhaseOffsets.h"
-#include "Scheduler/Scheduler.h"
+#include "SurfaceFlingerDefaultFactory.h"
 
 namespace android::surfaceflinger {
 
 sp<SurfaceFlinger> createSurfaceFlinger() {
-    class Factory final : public surfaceflinger::Factory {
-    public:
-        Factory() = default;
-        ~Factory() = default;
-
-        std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override {
-            return std::make_unique<android::impl::DispSync>(name, hasSyncFramework);
-        }
-
-        std::unique_ptr<EventControlThread> createEventControlThread(
-                SetVSyncEnabled setVSyncEnabled) override {
-            return std::make_unique<android::impl::EventControlThread>(std::move(setVSyncEnabled));
-        }
-
-        std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override {
-            return std::make_unique<android::impl::HWComposer>(
-                    std::make_unique<Hwc2::impl::Composer>(serviceName));
-        }
-
-        std::unique_ptr<MessageQueue> createMessageQueue() override {
-            return std::make_unique<android::impl::MessageQueue>();
-        }
-
-        std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
-            return std::make_unique<scheduler::impl::PhaseOffsets>();
-        }
-
-        std::unique_ptr<Scheduler> createScheduler(
-                SetVSyncEnabled setVSyncEnabled,
-                const scheduler::RefreshRateConfigs& configs) override {
-            return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs);
-        }
-
-        std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(
-                SurfaceFlinger* flinger) override {
-            return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
-        }
-
-        sp<StartPropertySetThread> createStartPropertySetThread(
-                bool timestampPropertyValue) override {
-            return new StartPropertySetThread(timestampPropertyValue);
-        }
-
-        sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
-            return new DisplayDevice(std::move(creationArgs));
-        }
-
-        sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
-                                              uint32_t layerCount, uint64_t usage,
-                                              std::string requestorName) override {
-            return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
-        }
-
-        void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
-                               sp<IGraphicBufferConsumer>* outConsumer,
-                               bool consumerIsSurfaceFlinger) override {
-            BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
-        }
-
-        std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
-                const sp<IGraphicBufferProducer>& producer) override {
-            return surfaceflinger::impl::createNativeWindowSurface(producer);
-        }
-
-        std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
-            return compositionengine::impl::createCompositionEngine();
-        }
-
-        sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override {
-            return new ContainerLayer(args);
-        }
-
-        sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override {
-            return new BufferQueueLayer(args);
-        }
-
-        sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override {
-            return new BufferStateLayer(args);
-        }
-
-        sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override {
-            return new ColorLayer(args);
-        }
-    };
-    static Factory factory;
+    static DefaultFactory factory;
 
     return new SurfaceFlinger(factory);
 }
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index d6b9b60..d021fc2 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -19,18 +19,20 @@
     srcs: [
         "BufferGenerator.cpp",
         "Credentials_test.cpp",
-	"DereferenceSurfaceControl_test.cpp",
+        "DereferenceSurfaceControl_test.cpp",
         "DisplayActiveConfig_test.cpp",
-	"InvalidHandles_test.cpp",
+        "InvalidHandles_test.cpp",
         "LayerCallback_test.cpp",
-	"LayerRenderTypeTransaction_test.cpp",
-	"LayerTransaction_test.cpp",
-	"LayerTypeAndRenderTypeTransaction_test.cpp",
-	"LayerTypeTransaction_test.cpp",
-	"LayerUpdate_test.cpp",
-	"MultiDisplayLayerBounds_test.cpp",
-	"RelativeZ_test.cpp",
-	"Stress_test.cpp",
+        "LayerRenderTypeTransaction_test.cpp",
+        "LayerTransaction_test.cpp",
+        "LayerTypeAndRenderTypeTransaction_test.cpp",
+        "LayerTypeTransaction_test.cpp",
+        "LayerUpdate_test.cpp",
+        "MirrorLayer_test.cpp",
+        "MultiDisplayLayerBounds_test.cpp",
+        "RelativeZ_test.cpp",
+        "SetGeometry_test.cpp",
+        "Stress_test.cpp",
         "SurfaceInterceptor_test.cpp",
         "VirtualDisplay_test.cpp",
     ],
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
new file mode 100644
index 0000000..0bcac1a
--- /dev/null
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2019 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 "LayerTransactionTest.h"
+
+namespace android {
+
+class MirrorLayerTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        mParentLayer = createColorLayer("Parent layer", Color::RED);
+        mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
+            t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+            t.setCrop_legacy(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
+            t.setPosition(mChildLayer, 50, 50);
+            t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+            t.setFlags(mChildLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+        });
+    }
+
+    virtual void TearDown() {
+        LayerTransactionTest::TearDown();
+        mParentLayer = 0;
+        mChildLayer = 0;
+    }
+
+    sp<SurfaceControl> mParentLayer;
+    sp<SurfaceControl> mChildLayer;
+};
+
+TEST_F(MirrorLayerTest, MirrorColorLayer) {
+    sp<SurfaceControl> grandchild =
+            createColorLayer("Grandchild layer", Color::BLUE, mChildLayer.get());
+    Transaction()
+            .setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+            .setCrop_legacy(grandchild, Rect(0, 0, 200, 200))
+            .show(grandchild)
+            .apply();
+
+    // Mirror mChildLayer
+    sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+    ASSERT_NE(mirrorLayer, nullptr);
+
+    // Add mirrorLayer as child of mParentLayer so it's shown on the display
+    Transaction()
+            .reparent(mirrorLayer, mParentLayer->getHandle())
+            .setPosition(mirrorLayer, 500, 500)
+            .show(mirrorLayer)
+            .apply();
+
+    {
+        SCOPED_TRACE("Initial Mirror");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    // Set color to white on grandchild layer.
+    Transaction().setColor(grandchild, half3{1, 1, 1}).apply();
+    {
+        SCOPED_TRACE("Updated Grandchild Layer Color");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    // Set color to black on child layer.
+    Transaction().setColor(mChildLayer, half3{0, 0, 0}).apply();
+    {
+        SCOPED_TRACE("Updated Child Layer Color");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+    }
+
+    // Remove grandchild layer
+    Transaction().reparent(grandchild, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed Grandchild Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLACK);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+    }
+
+    // Remove child layer
+    Transaction().reparent(mChildLayer, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed Child Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+    }
+
+    // Add grandchild layer to offscreen layer
+    Transaction().reparent(grandchild, mChildLayer->getHandle()).apply();
+    {
+        SCOPED_TRACE("Added Grandchild Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+    }
+
+    // Add child layer
+    Transaction().reparent(mChildLayer, mParentLayer->getHandle()).apply();
+    {
+        SCOPED_TRACE("Added Child Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+    }
+}
+
+TEST_F(MirrorLayerTest, MirrorBufferLayer) {
+    sp<SurfaceControl> bufferQueueLayer =
+            createLayer("BufferQueueLayer", 200, 200, 0, mChildLayer.get());
+    fillBufferQueueLayerColor(bufferQueueLayer, Color::BLUE, 200, 200);
+    Transaction().show(bufferQueueLayer).apply();
+
+    sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+    Transaction()
+            .reparent(mirrorLayer, mParentLayer->getHandle())
+            .setPosition(mirrorLayer, 500, 500)
+            .show(mirrorLayer)
+            .apply();
+
+    {
+        SCOPED_TRACE("Initial Mirror BufferQueueLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    fillBufferQueueLayerColor(bufferQueueLayer, Color::WHITE, 200, 200);
+    {
+        SCOPED_TRACE("Update BufferQueueLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    Transaction().reparent(bufferQueueLayer, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed BufferQueueLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    sp<SurfaceControl> bufferStateLayer =
+            createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState,
+                        mChildLayer.get());
+    fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200);
+    Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply();
+
+    {
+        SCOPED_TRACE("Initial Mirror BufferStateLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    fillBufferStateLayerColor(bufferStateLayer, Color::WHITE, 200, 200);
+    {
+        SCOPED_TRACE("Update BufferStateLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    Transaction().reparent(bufferStateLayer, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed BufferStateLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
new file mode 100644
index 0000000..dca06ec
--- /dev/null
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 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 "LayerTransactionTest.h"
+
+namespace android {
+
+class SetGeometryTest : public LayerTransactionTest {
+protected:
+    void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        mLayer = createLayer("Layer", mLayerWidth, mLayerHeight);
+        fillBufferQueueLayerColor(mLayer, Color::RED, mLayerWidth, mLayerHeight);
+        asTransaction([&](Transaction& t) { t.setLayer(mLayer, INT32_MAX - 1).show(mLayer); });
+
+        {
+            SCOPED_TRACE("init");
+            ScreenCapture::captureScreen(&sc);
+            sc->expectColor(Rect(0, 0, mLayerWidth, mLayerHeight), Color::RED);
+            sc->expectBorder(Rect(0, 0, mLayerWidth, mLayerHeight), Color::BLACK);
+        }
+    }
+
+    void TearDown() {
+        LayerTransactionTest::TearDown();
+        sc = 0;
+        mLayer = 0;
+    }
+
+    std::unique_ptr<ScreenCapture> sc;
+    sp<SurfaceControl> mLayer;
+    const int mLayerWidth = 100;
+    const int mLayerHeight = 200;
+};
+
+TEST_F(SetGeometryTest, SourceAtZeroNoScale) {
+    Rect source = Rect(0, 0, 30, 30);
+    Rect dest = Rect(60, 60, 90, 90);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+    {
+        SCOPED_TRACE("geometry applied");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+}
+
+TEST_F(SetGeometryTest, SourceNotAtZero) {
+    Rect source = Rect(40, 40, 70, 70);
+    Rect dest = Rect(60, 60, 90, 90);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+    {
+        SCOPED_TRACE("geometry applied");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+}
+
+TEST_F(SetGeometryTest, Scale) {
+    Rect source = Rect(0, 0, 100, 200);
+    Rect dest = Rect(0, 0, 200, 400);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+    {
+        SCOPED_TRACE("Scaled by 2");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+
+    dest = Rect(0, 0, 50, 100);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+    {
+        SCOPED_TRACE("Scaled by .5");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6b4634a..b196684 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*"
+            "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*:SetGeometryTest.*"
         }
 }
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index c949d7c..67faa57 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -127,7 +127,6 @@
 public:
     class MockComposerClient : public FakeComposerClient {
     public:
-        MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
         MOCK_METHOD4(getDisplayAttribute,
                      Error(Display display, Config config, IComposerClient::Attribute attribute,
                            int32_t* outValue));
@@ -176,9 +175,6 @@
     android::hardware::ProcessState::self()->startThreadPool();
     android::ProcessState::self()->startThreadPool();
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                            Return(Error::NONE)));
     // Primary display will be queried twice for all 5 attributes. One
     // set of queries comes from the SurfaceFlinger proper an the
     // other set from the VR composer.
@@ -270,10 +266,6 @@
 TEST_F(DisplayTest, Hotplug) {
     ALOGD("DisplayTest::Hotplug");
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                                  Return(Error::NONE)));
     // The attribute queries will get done twice. This is for defaults
     EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
             .Times(2 * 3)
@@ -381,10 +373,6 @@
 
     mMockComposer->clearFrames();
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                                  Return(Error::NONE)));
     // The attribute queries will get done twice. This is for defaults
     EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
             .Times(2 * 3)
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 8d98af6..2183d34 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -52,11 +52,10 @@
         "RegionSamplingTest.cpp",
         "TimeStatsTest.cpp",
         "FrameTracerTest.cpp",
+        "TransactionApplicationTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplay.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
-        "mock/gui/MockGraphicBufferConsumer.cpp",
-        "mock/gui/MockGraphicBufferProducer.cpp",
         "mock/MockDispSync.cpp",
         "mock/MockEventControlThread.cpp",
         "mock/MockEventThread.cpp",
@@ -71,6 +70,7 @@
         "libgmock",
         "libcompositionengine",
         "libcompositionengine_mocks",
+        "libgui_mocks",
         "libperfetto_client_experimental",
         "librenderengine_mocks",
         "libtimestats",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index b6fa2a6..8aff096 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -1039,6 +1039,26 @@
     static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
 };
 
+struct ForcedClientCompositionViaDebugOptionResultVariant : public CompositionResultBaseVariant {
+    static void setupLayerState(CompositionTest* test, sp<Layer>) {
+        test->mFlinger.mutableDebugDisableHWC() = true;
+    }
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
 struct EmptyScreenshotResultVariant {
     static void setupLayerState(CompositionTest*, sp<Layer>) {}
 
@@ -1350,5 +1370,23 @@
             NoCompositionTypeVariant, REScreenshotResultVariant>>();
 }
 
+/* ------------------------------------------------------------------------
+ *  Client composition forced through debug/developer settings
+ */
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index fcce57b..b1a4951 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -24,6 +24,8 @@
 #include <compositionengine/mock/DisplaySurface.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <gui/mock/GraphicBufferConsumer.h>
+#include <gui/mock/GraphicBufferProducer.h>
 #include <log/log.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <ui/DebugUtils.h>
@@ -38,8 +40,6 @@
 #include "mock/MockMessageQueue.h"
 #include "mock/MockNativeWindowSurface.h"
 #include "mock/MockSurfaceInterceptor.h"
-#include "mock/gui/MockGraphicBufferConsumer.h"
-#include "mock/gui/MockGraphicBufferProducer.h"
 #include "mock/system/window/MockNativeWindow.h"
 
 namespace android {
@@ -445,10 +445,6 @@
     }
 
     static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
-                                        HWC_DISPLAY_TYPE)),
-                                Return(Error::NONE)));
         EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
         EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b77f82a..b85c1b6 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -35,7 +35,7 @@
 #include "Scheduler/RefreshRateConfigs.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerFactory.h"
+#include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
 #include "TestableScheduler.h"
 
@@ -232,6 +232,8 @@
     auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
     auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
 
+    auto& mutableStateLock() { return mFlinger->mStateLock; }
+
     void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
         layer->mDrawingState.sidebandStream = sidebandStream;
         layer->mSidebandStream = sidebandStream;
@@ -320,6 +322,22 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
+    auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
+
+    auto setTransactionState(const Vector<ComposerState>& states,
+                             const Vector<DisplayState>& displays, uint32_t flags,
+                             const sp<IBinder>& applyToken,
+                             const InputWindowCommands& inputWindowCommands,
+                             int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+                             bool hasListenerCallbacks,
+                             std::vector<ListenerCallbacks>& listenerCallbacks) {
+        return mFlinger->setTransactionState(states, displays, flags, applyToken,
+                                             inputWindowCommands, desiredPresentTime, uncacheBuffer,
+                                             hasListenerCallbacks, listenerCallbacks);
+    }
+
+    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -356,6 +374,7 @@
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
     auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
+    auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
 
     auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
     auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
new file mode 100644
index 0000000..a465388
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CompositionTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::Return;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class TransactionApplicationTest : public testing::Test {
+public:
+    TransactionApplicationTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+        mFlinger.mutableEventQueue().reset(mMessageQueue);
+        setupScheduler();
+    }
+
+    ~TransactionApplicationTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    void setupScheduler() {
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
+
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+        mFlinger.setupScheduler(std::unique_ptr<mock::DispSync>(mPrimaryDispSync),
+                                std::make_unique<mock::EventControlThread>(),
+                                std::move(eventThread), std::move(sfEventThread));
+    }
+
+    TestableScheduler* mScheduler;
+    TestableSurfaceFlinger mFlinger;
+
+    std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+    struct TransactionInfo {
+        Vector<ComposerState> states;
+        Vector<DisplayState> displays;
+        uint32_t flags = 0;
+        sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+        InputWindowCommands inputWindowCommands;
+        int64_t desiredPresentTime = -1;
+        client_cache_t uncacheBuffer;
+    };
+
+    void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
+        EXPECT_EQ(0, info.states.size());
+        EXPECT_EQ(0, state.states.size());
+
+        EXPECT_EQ(0, info.displays.size());
+        EXPECT_EQ(0, state.displays.size());
+        EXPECT_EQ(info.flags, state.flags);
+        EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
+    }
+
+    void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
+                     int64_t desiredPresentTime) {
+        mTransactionNumber++;
+        transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
+        transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
+        transaction.desiredPresentTime = desiredPresentTime;
+    }
+
+    void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillOnce(Return(systemTime()));
+        TransactionInfo transaction;
+        setupSingle(transaction, flags, syncInputWindows,
+                    /*desiredPresentTime*/ -1);
+        nsecs_t applicationTime = systemTime();
+        mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                     transaction.applyToken, transaction.inputWindowCommands,
+                                     transaction.desiredPresentTime, transaction.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // This transaction should not have been placed on the transaction queue.
+        // If transaction is synchronous or syncs input windows, SF
+        // applyTransactionState should time out (5s) wating for SF to commit
+        // the transaction or to receive a signal that syncInputWindows has
+        // completed.  If this is animation, it should not time out waiting.
+        nsecs_t returnedTime = systemTime();
+        if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
+            EXPECT_GE(returnedTime, applicationTime + s2ns(5));
+        } else {
+            EXPECT_LE(returnedTime, applicationTime + s2ns(5));
+        }
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(0, transactionQueue.size());
+    }
+
+    void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+        // first check will see desired present time has not passed,
+        // but afterwards it will look like the desired present time has passed
+        nsecs_t time = systemTime();
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime())
+                .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+        TransactionInfo transaction;
+        setupSingle(transaction, flags, syncInputWindows,
+                    /*desiredPresentTime*/ time + s2ns(1));
+        nsecs_t applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                     transaction.applyToken, transaction.inputWindowCommands,
+                                     transaction.desiredPresentTime, transaction.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        nsecs_t returnedTime = systemTime();
+        EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
+        // This transaction should have been placed on the transaction queue
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(1, transactionQueue.size());
+    }
+
+    void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        nsecs_t time = systemTime();
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime())
+                .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+        // transaction that should go on the pending thread
+        TransactionInfo transactionA;
+        setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+                    /*desiredPresentTime*/ time + s2ns(1));
+
+        // transaction that would not have gone on the pending thread if not
+        // blocked
+        TransactionInfo transactionB;
+        setupSingle(transactionB, flags, syncInputWindows,
+                    /*desiredPresentTime*/ -1);
+
+        nsecs_t applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+                                     transactionA.applyToken, transactionA.inputWindowCommands,
+                                     transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // This thread should not have been blocked by the above transaction
+        // (5s is the timeout period that applyTransactionState waits for SF to
+        // commit the transaction)
+        EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+
+        applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transactionB.states, transactionB.displays, transactionB.flags,
+                                     transactionB.applyToken, transactionB.inputWindowCommands,
+                                     transactionB.desiredPresentTime, transactionB.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // this thread should have been blocked by the above transaction
+        // if this is an animation, this thread should be blocked for 5s
+        // in setTransactionState waiting for transactionA to flush.  Otherwise,
+        // the transaction should be placed on the pending queue
+        if (flags & ISurfaceComposer::eAnimation) {
+            EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
+        } else {
+            EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+        }
+
+        // check that there is one binder on the pending queue.
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(1, transactionQueue.size());
+
+        auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+        EXPECT_EQ(2, transactionStates.size());
+
+        auto& transactionStateA = transactionStates.front();
+        transactionStates.pop();
+        checkEqual(transactionA, transactionStateA);
+        auto& transactionStateB = transactionStates.front();
+        checkEqual(transactionB, transactionStateB);
+    }
+
+    bool mHasListenerCallbacks = false;
+    std::vector<ListenerCallbacks> mCallbacks;
+    int mTransactionNumber = 0;
+};
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
+    ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+    // called in SurfaceFlinger::signalTransaction
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // nsecs_t time = systemTime();
+    EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime())
+            .WillOnce(Return(nsecs_t(5 * 1e8)))
+            .WillOnce(Return(s2ns(2)));
+    TransactionInfo transactionA; // transaction to go on pending queue
+    setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+                /*desiredPresentTime*/ s2ns(1));
+    mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+                                 transactionA.applyToken, transactionA.inputWindowCommands,
+                                 transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+                                 mHasListenerCallbacks, mCallbacks);
+
+    auto& transactionQueue = mFlinger.getTransactionQueue();
+    ASSERT_EQ(1, transactionQueue.size());
+
+    auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+    ASSERT_EQ(1, transactionStates.size());
+
+    auto& transactionState = transactionStates.front();
+    checkEqual(transactionA, transactionState);
+
+    // because flushing uses the cached expected present time, we send an empty
+    // transaction here (sending a null applyToken to fake it as from a
+    // different process) to re-query and reset the cached expected present time
+    TransactionInfo empty;
+    empty.applyToken = sp<IBinder>();
+    mFlinger.setTransactionState(empty.states, empty.displays, empty.flags, empty.applyToken,
+                                 empty.inputWindowCommands, empty.desiredPresentTime,
+                                 empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
+
+    // flush transaction queue should flush as desiredPresentTime has
+    // passed
+    mFlinger.flushTransactionQueues();
+
+    EXPECT_EQ(0, transactionQueue.size());
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Animation) {
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
+    NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
+    PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Animation) {
+    PlaceOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
+    PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) {
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) {
+    BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 3c7e1da..98c6aa0 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -41,7 +41,7 @@
 using android::hardware::graphics::composer::V2_1::IComposer;
 using android::hardware::graphics::composer::V2_1::IComposerCallback;
 using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_3::IComposerClient;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
 
 class Composer : public Hwc2::Composer {
 public:
@@ -71,7 +71,6 @@
     MOCK_METHOD2(getDisplayName, Error(Display, std::string*));
     MOCK_METHOD4(getDisplayRequests,
                  Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
-    MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
     MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
     MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
     MOCK_METHOD1(getPerFrameMetadataKeys,
@@ -118,10 +117,11 @@
     MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t));
     MOCK_METHOD4(getDisplayedContentSample,
                  Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
-    MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
     MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
                  Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
     MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+    MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
+    MOCK_METHOD2(getDisplayConnectionType, Error(Display, IComposerClient::DisplayConnectionType*));
 };
 
 } // namespace mock