Merge "Add flag for controling app image generation" into pi-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 57745ef..21d9ace 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -116,7 +116,8 @@
     { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
     { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
     { "adb",        "ADB",              ATRACE_TAG_ADB, { } },
-    { "vibrator",   "Vibrator",         ATRACE_TAG_VIBRATOR, {}},
+    { "vibrator",   "Vibrator",         ATRACE_TAG_VIBRATOR, { } },
+    { "aidl",       "AIDL calls",       ATRACE_TAG_AIDL, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
@@ -774,22 +775,10 @@
     return ok;
 }
 
-// Set all the kernel tracing settings to the desired state for this trace
-// capture.
-static bool setUpTrace()
+static bool setUpUserspaceTracing()
 {
     bool ok = true;
 
-    // Set up the tracing options.
-    ok &= setCategoriesEnableFromFile(g_categoriesFile);
-    ok &= setTraceOverwriteEnable(g_traceOverwrite);
-    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
-    // TODO: Re-enable after stabilization
-    //ok &= setCmdlineSize();
-    ok &= setClock();
-    ok &= setPrintTgidEnableIfPresent(true);
-    ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
-
     // Set up the tags property.
     uint64_t tags = 0;
     for (size_t i = 0; i < arraysize(k_categories); i++) {
@@ -827,6 +816,37 @@
         ok &= ServiceUtility::PokeServices();
     }
 
+    return ok;
+}
+
+static void cleanUpUserspaceTracing()
+{
+    setTagsProperty(0);
+    clearAppProperties();
+    pokeBinderServices();
+
+    if (g_tracePdx) {
+        ServiceUtility::PokeServices();
+    }
+}
+
+
+// Set all the kernel tracing settings to the desired state for this trace
+// capture.
+static bool setUpKernelTracing()
+{
+    bool ok = true;
+
+    // Set up the tracing options.
+    ok &= setCategoriesEnableFromFile(g_categoriesFile);
+    ok &= setTraceOverwriteEnable(g_traceOverwrite);
+    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
+    // TODO: Re-enable after stabilization
+    //ok &= setCmdlineSize();
+    ok &= setClock();
+    ok &= setPrintTgidEnableIfPresent(true);
+    ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
+
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
     ok &= disableKernelTraceEvents();
@@ -854,20 +874,11 @@
 }
 
 // Reset all the kernel tracing settings to their default state.
-static void cleanUpTrace()
+static void cleanUpKernelTracing()
 {
     // Disable all tracing that we're able to.
     disableKernelTraceEvents();
 
-    // Reset the system properties.
-    setTagsProperty(0);
-    clearAppProperties();
-    pokeBinderServices();
-
-    if (g_tracePdx) {
-        ServiceUtility::PokeServices();
-    }
-
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
     setTraceBufferSizeKB(1);
@@ -875,7 +886,6 @@
     setKernelTraceFuncs(NULL);
 }
 
-
 // Enable tracing in the kernel.
 static bool startTrace()
 {
@@ -1107,6 +1117,7 @@
     bool traceStop = true;
     bool traceDump = true;
     bool traceStream = false;
+    bool onlyUserspace = false;
 
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         showHelp(argv[0]);
@@ -1122,12 +1133,13 @@
         int ret;
         int option_index = 0;
         static struct option long_options[] = {
-            {"async_start",     no_argument, 0,  0 },
-            {"async_stop",      no_argument, 0,  0 },
-            {"async_dump",      no_argument, 0,  0 },
-            {"list_categories", no_argument, 0,  0 },
-            {"stream",          no_argument, 0,  0 },
-            {           0,                0, 0,  0 }
+            {"async_start",       no_argument, 0,  0 },
+            {"async_stop",        no_argument, 0,  0 },
+            {"async_dump",        no_argument, 0,  0 },
+            {"only_userspace",    no_argument, 0,  0 },
+            {"list_categories",   no_argument, 0,  0 },
+            {"stream",            no_argument, 0,  0 },
+            {           0,                  0, 0,  0 }
         };
 
         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
@@ -1197,6 +1209,8 @@
                     async = true;
                     traceStart = false;
                     traceStop = false;
+                } else if (!strcmp(long_options[option_index].name, "only_userspace")) {
+                    onlyUserspace = true;
                 } else if (!strcmp(long_options[option_index].name, "stream")) {
                     traceStream = true;
                     traceDump = false;
@@ -1214,6 +1228,14 @@
         }
     }
 
+    if (onlyUserspace) {
+        if (!async || !(traceStart || traceStop)) {
+            fprintf(stderr, "--only_userspace can only be used with "
+                    "--async_start or --async_stop\n");
+            exit(1);
+        }
+    }
+
     registerSigHandler();
 
     if (g_initialSleepSecs > 0) {
@@ -1221,13 +1243,19 @@
     }
 
     bool ok = true;
+
     if (traceStart) {
-        ok &= setUpTrace();
+        ok &= setUpUserspaceTracing();
+    }
+
+    if (ok && traceStart && !onlyUserspace) {
+        ok &= setUpKernelTracing();
         ok &= startTrace();
     }
 
     if (ok && traceStart) {
-        if (!traceStream) {
+
+        if (!traceStream && !onlyUserspace) {
             printf("capturing trace...");
             fflush(stdout);
         }
@@ -1237,9 +1265,12 @@
         // contain entries from only one CPU can cause "begin" entries without a
         // matching "end" entry to show up if a task gets migrated from one CPU to
         // another.
-        ok = clearTrace();
+        if (!onlyUserspace)
+            ok = clearTrace();
 
-        writeClockSyncMarker();
+        if (!onlyUserspace)
+            writeClockSyncMarker();
+
         if (ok && !async && !traceStream) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
@@ -1258,10 +1289,10 @@
     }
 
     // Stop the trace and restore the default settings.
-    if (traceStop)
+    if (traceStop && !onlyUserspace)
         stopTrace();
 
-    if (ok && traceDump) {
+    if (ok && traceDump && !onlyUserspace) {
         if (!g_traceAborted) {
             printf(" done\n");
             fflush(stdout);
@@ -1288,8 +1319,11 @@
     }
 
     // Reset the trace buffer size to 1.
-    if (traceStop)
-        cleanUpTrace();
+    if (traceStop) {
+        cleanUpUserspaceTracing();
+        if (!onlyUserspace)
+            cleanUpKernelTracing();
+    }
 
     return g_traceAborted ? 1 : 0;
 }
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 3ec0163..cb6d0c6 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -82,6 +82,28 @@
     chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
     chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/enable
 
+    # disk
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_begin/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_end/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_begin/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/block/block_rq_issue/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
+    chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+
 # Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
     write /sys/kernel/tracing/tracing_on 0
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index 9d632cc..93a29ba 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -19,25 +19,3 @@
     chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
     chmod 0666 /sys/kernel/tracing/events/ipi/enable
     chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
-
-    # disk
-    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
-    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
-    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_begin/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
-    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_end/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
-    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_begin/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
-    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
-    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
-    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
-    chmod 0666 /sys/kernel/tracing/events/block/block_rq_issue/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
-    chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 83e30a2..33e35f7 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <grp.h>
+#include <poll.h>
 #include <pwd.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -35,6 +36,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/macros.h>
 #include <log/log.h>
 
 uint64_t Nanotime() {
@@ -98,13 +100,25 @@
     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     capheader.pid = 0;
 
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[0].inheritable = 0;
-    capdata[1].inheritable = 0;
+    if (capget(&capheader, &capdata[0]) != 0) {
+        MYLOGE("capget failed: %s\n", strerror(errno));
+        return false;
+    }
 
-    if (capset(&capheader, &capdata[0]) < 0) {
-        MYLOGE("capset failed: %s\n", strerror(errno));
+    const uint32_t cap_syslog_mask = CAP_TO_MASK(CAP_SYSLOG);
+    const uint32_t cap_syslog_index = CAP_TO_INDEX(CAP_SYSLOG);
+    bool has_cap_syslog = (capdata[cap_syslog_index].effective & cap_syslog_mask) != 0;
+
+    memset(&capdata, 0, sizeof(capdata));
+    if (has_cap_syslog) {
+        // Only attempt to keep CAP_SYSLOG if it was present to begin with.
+        capdata[cap_syslog_index].permitted |= cap_syslog_mask;
+        capdata[cap_syslog_index].effective |= cap_syslog_mask;
+    }
+
+    if (capset(&capheader, &capdata[0]) != 0) {
+        MYLOGE("capset({%#x, %#x}) failed: %s\n", capdata[0].effective,
+               capdata[1].effective, strerror(errno));
         return false;
     }
 
@@ -142,22 +156,16 @@
         return 0;
     }
     bool newline = false;
-    fd_set read_set;
-    timeval tm;
     while (true) {
-        FD_ZERO(&read_set);
-        FD_SET(fd, &read_set);
-        /* Timeout if no data is read for 30 seconds. */
-        tm.tv_sec = 30;
-        tm.tv_usec = 0;
-        uint64_t elapsed = Nanotime();
-        int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, nullptr, nullptr, &tm));
+        uint64_t start_time = Nanotime();
+        pollfd fds[] = { { .fd = fd, .events = POLLIN } };
+        int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), 30 * 1000));
         if (ret == -1) {
-            dprintf(out_fd, "*** %s: select failed: %s\n", path, strerror(errno));
+            dprintf(out_fd, "*** %s: poll failed: %s\n", path, strerror(errno));
             newline = true;
             break;
         } else if (ret == 0) {
-            elapsed = Nanotime() - elapsed;
+            uint64_t elapsed = Nanotime() - start_time;
             dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
             newline = true;
             break;
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 371533c..9d0c30b 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -32,14 +32,20 @@
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
+
+#include <chrono>
+#include <functional>
+#include <future>
 #include <memory>
 #include <regex>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -53,6 +59,7 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 #include <serviceutils/PriorityDumper.h>
+#include <utils/StrongPointer.h>
 #include "DumpstateInternal.h"
 #include "DumpstateSectionReporter.h"
 #include "DumpstateService.h"
@@ -112,19 +119,6 @@
 static const std::string ANR_DIR = "/data/anr/";
 static const std::string ANR_FILE_PREFIX = "anr_";
 
-struct DumpData {
-    std::string name;
-    int fd;
-    time_t mtime;
-};
-
-static bool operator<(const DumpData& d1, const DumpData& d2) {
-    return d1.mtime > d2.mtime;
-}
-
-static std::unique_ptr<std::vector<DumpData>> tombstone_data;
-static std::unique_ptr<std::vector<DumpData>> anr_data;
-
 // TODO: temporary variables and functions used during C++ refactoring
 static Dumpstate& ds = Dumpstate::GetInstance();
 static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
@@ -167,15 +161,20 @@
  * 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) {
+static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
+                                        const std::string& file_prefix,
+                                        bool limit_by_mtime,
+                                        bool limit_by_count = true) {
     const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
 
-    std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
     std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
 
+    if (dump_dir == nullptr) {
+        MYLOGW("Unable to open directory %s: %s\n", dir_path.c_str(), strerror(errno));
+        return std::vector<DumpData>();
+    }
+
+    std::vector<DumpData> dump_data;
     struct dirent* entry = nullptr;
     while ((entry = readdir(dump_dir.get()))) {
         if (entry->d_type != DT_REG) {
@@ -191,13 +190,13 @@
         android::base::unique_fd fd(
             TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
         if (fd == -1) {
-            MYLOGW("Unable to open dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+            MYLOGW("Unable to open dump file %s: %s\n", abs_path.c_str(), strerror(errno));
             break;
         }
 
         struct stat st = {};
         if (fstat(fd, &st) == -1) {
-            MYLOGW("Unable to stat dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+            MYLOGW("Unable to stat dump file %s: %s\n", abs_path.c_str(), strerror(errno));
             continue;
         }
 
@@ -206,18 +205,19 @@
             continue;
         }
 
-        DumpData data = {.name = abs_path, .fd = fd.release(), .mtime = st.st_mtime};
-
-        dump_data->push_back(data);
+        dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
     }
 
-    std::sort(dump_data->begin(), dump_data->end());
+    // 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());
+    if (limit_by_count && dump_data.size() > 10) {
+        dump_data.erase(dump_data.begin() + 10, dump_data.end());
     }
 
-    return dump_data.release();
+    return dump_data;
 }
 
 static bool AddDumps(const std::vector<DumpData>::const_iterator start,
@@ -252,12 +252,6 @@
     return dumped;
 }
 
-static void CloseDumpFds(const std::vector<DumpData>* dumps) {
-    for (auto it = dumps->begin(); it != dumps->end(); ++it) {
-        close(it->fd);
-    }
-}
-
 // for_each_pid() callback to get mount info about a process.
 void do_mountinfo(int pid, const char* name __attribute__((unused))) {
     char path[PATH_MAX];
@@ -1002,15 +996,15 @@
     }
 
     // Add a specific message for the first ANR Dump.
-    if (anr_data->size() > 0) {
-        AddDumps(anr_data->begin(), anr_data->begin() + 1,
+    if (ds.anr_data_.size() > 0) {
+        AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
                  "VM TRACES AT LAST ANR", add_to_zip);
 
         // The "last" ANR will always be included as separate entry in the zip file. In addition,
         // it will be present in the body of the main entry if |add_to_zip| == false.
         //
         // Historical ANRs are always included as separate entries in the bugreport zip file.
-        AddDumps(anr_data->begin() + ((add_to_zip) ? 1 : 0), anr_data->end(),
+        AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
                  "HISTORICAL ANR", true /* add_to_zip */);
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
@@ -1172,6 +1166,10 @@
 static void RunDumpsysProto(const std::string& title, int priority,
                             std::chrono::milliseconds timeout,
                             std::chrono::milliseconds service_timeout) {
+    if (!ds.IsZipping()) {
+        MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
+        return;
+    }
     sp<android::IServiceManager> sm = defaultServiceManager();
     Dumpsys dumpsys(sm.get());
     Vector<String16> args;
@@ -1357,7 +1355,7 @@
 
     // NOTE: tombstones are always added as separate entries in the zip archive
     // and are not interspersed with the main report.
-    const bool tombstones_dumped = AddDumps(tombstone_data->begin(), tombstone_data->end(),
+    const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
                                             "TOMBSTONE", true /* add_to_zip */);
     if (!tombstones_dumped) {
         printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
@@ -1542,77 +1540,101 @@
     printf("== Board\n");
     printf("========================================================\n");
 
-    ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
-    if (dumpstate_device == nullptr) {
-        MYLOGE("No IDumpstateDevice implementation\n");
-        return;
-    }
-
     if (!IsZipping()) {
         MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
         return;
     }
 
-    std::string path[NUM_OF_DUMPS];
-    android::base::unique_fd fd[NUM_OF_DUMPS];
-    int numFds = 0;
-
+    std::vector<std::string> paths;
+    std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
-        path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
-        MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
+        paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]);
+        remover.emplace_back(android::base::make_scope_guard(std::bind(
+            [](std::string path) {
+                if (remove(path.c_str()) != 0 && errno != ENOENT) {
+                    MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+                }
+            },
+            paths[i])));
+    }
 
-        fd[i] = android::base::unique_fd(
-            TEMP_FAILURE_RETRY(open(path[i].c_str(),
-            O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
-        if (fd[i] < 0) {
-            MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
-            return;
-        } else {
-            numFds++;
+    // Given that bugreport is required to diagnose failures, it's better to
+    // drop the result of IDumpstateDevice than to block the rest of bugreport
+    // for an arbitrary amount of time.
+    std::packaged_task<std::unique_ptr<ssize_t[]>()>
+        dumpstate_task([paths]() -> std::unique_ptr<ssize_t[]> {
+            ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
+            if (dumpstate_device == nullptr) {
+                MYLOGE("No IDumpstateDevice implementation\n");
+                return nullptr;
+            }
+
+            using ScopedNativeHandle =
+                std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
+            ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
+                                      [](native_handle_t* handle) {
+                                          native_handle_close(handle);
+                                          native_handle_delete(handle);
+                                      });
+            if (handle == nullptr) {
+                MYLOGE("Could not create native_handle\n");
+                return nullptr;
+            }
+
+            for (size_t i = 0; i < paths.size(); i++) {
+                MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
+
+                android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+                    open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                         S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+                if (fd < 0) {
+                    MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
+                    return nullptr;
+                }
+                handle.get()->data[i] = fd.release();
+            }
+
+            android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
+            if (!status.isOk()) {
+                MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+                return nullptr;
+            }
+            auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
+            for (size_t i = 0; i < paths.size(); i++) {
+                struct stat s;
+                if (fstat(handle.get()->data[i], &s) == -1) {
+                    MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
+                           strerror(errno));
+                    file_sizes[i] = -1;
+                    continue;
+                }
+                file_sizes[i] = s.st_size;
+            }
+            return file_sizes;
+        });
+    auto result = dumpstate_task.get_future();
+    std::thread(std::move(dumpstate_task)).detach();
+    if (result.wait_for(30s) != std::future_status::ready) {
+        MYLOGE("dumpstateBoard timed out after 30s\n");
+        return;
+    }
+    std::unique_ptr<ssize_t[]> file_sizes = result.get();
+    if (file_sizes == nullptr) {
+        return;
+    }
+
+    for (size_t i = 0; i < paths.size(); i++) {
+        if (file_sizes[i] == -1) {
+            continue;
         }
-    }
-
-    native_handle_t *handle = native_handle_create(numFds, 0);
-    if (handle == nullptr) {
-        MYLOGE("Could not create native_handle\n");
-        return;
-    }
-
-    for (int i = 0; i < numFds; i++) {
-        handle->data[i] = fd[i].release();
-    }
-
-    // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
-    android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
-    if (!status.isOk()) {
-        MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
-        native_handle_close(handle);
-        native_handle_delete(handle);
-        return;
-    }
-
-    for (int i = 0; i < numFds; i++) {
-        struct stat s;
-        if (fstat(handle->data[i], &s) == -1) {
-            MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
-        } else if (s.st_size > 0) {
-            AddZipEntry(kDumpstateBoardFiles[i], path[i]);
-        } else {
+        if (file_sizes[i] == 0) {
             MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+            continue;
         }
+        AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
     }
 
     printf("*** See dumpstate-board.txt entry ***\n");
-
-    native_handle_close(handle);
-    native_handle_delete(handle);
-
-    for (int i = 0; i < numFds; i++) {
-        if (remove(path[i].c_str()) != 0) {
-            MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
-        }
-    }
 }
 
 static void ShowUsageAndExit(int exitCode = 1) {
@@ -1643,20 +1665,8 @@
     ShowUsageAndExit();
 }
 
-static void sig_handler(int) {
-    _exit(EXIT_FAILURE);
-}
-
 static void register_sig_handler() {
-    struct sigaction sa;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    sa.sa_handler = sig_handler;
-    sigaction(SIGPIPE, &sa, NULL); // broken pipe
-    sigaction(SIGSEGV, &sa, NULL); // segment fault
-    sigaction(SIGINT, &sa, NULL); // ctrl-c
-    sigaction(SIGTERM, &sa, NULL); // killed
-    sigaction(SIGQUIT, &sa, NULL); // quit
+    signal(SIGPIPE, SIG_IGN);
 }
 
 bool Dumpstate::FinishZipFile() {
@@ -2109,8 +2119,8 @@
         dump_traces_path = dump_traces();
 
         /* Run some operations that require root. */
-        tombstone_data.reset(GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
-        anr_data.reset(GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping()));
+        ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
+        ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
 
         ds.AddDir(RECOVERY_DIR, true);
         ds.AddDir(RECOVERY_DATA_DIR, true);
@@ -2283,8 +2293,8 @@
         close(ds.control_socket_fd_);
     }
 
-    CloseDumpFds(tombstone_data.get());
-    CloseDumpFds(anr_data.get());
+    ds.tombstone_data_.clear();
+    ds.anr_data_.clear();
 
     return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ea4fccd..b220013 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include <android-base/macros.h>
+#include <android-base/unique_fd.h>
 #include <android/os/IDumpstateListener.h>
 #include <utils/StrongPointer.h>
 #include <ziparchive/zip_writer.h>
@@ -159,6 +160,20 @@
 static std::string VERSION_DEFAULT = "default";
 
 /*
+ * Structure that contains the information of an open dump file.
+ */
+struct DumpData {
+    // Path of the file.
+    std::string name;
+
+    // Open file descriptor for the file.
+    android::base::unique_fd fd;
+
+    // Modification time of the file.
+    time_t mtime;
+};
+
+/*
  * Main class driving a bugreport generation.
  *
  * Currently, it only contains variables that are accessed externally, but gradually the functions
@@ -350,6 +365,12 @@
     std::string notification_title;
     std::string notification_description;
 
+    // List of open tombstone dump files.
+    std::vector<DumpData> tombstone_data_;
+
+    // List of open ANR dump files.
+    std::vector<DumpData> anr_data_;
+
   private:
     // Used by GetInstance() only.
     Dumpstate(const std::string& version = VERSION_CURRENT);
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e53a223..833ffbf 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <fstream>
 #include <fts.h>
+#include <functional>
 #include <inttypes.h>
 #include <regex>
 #include <stdlib.h>
@@ -2412,27 +2413,25 @@
 
 // This kernel feature is experimental.
 // TODO: remove local definition once upstreamed
-#ifndef FS_IOC_SET_FSVERITY
-struct fsverity_set {
-    __u64 offset;
-    __u64 flags;
+#ifndef FS_IOC_ENABLE_VERITY
+
+#define FS_IOC_ENABLE_VERITY           _IO('f', 133)
+#define FS_IOC_SET_VERITY_MEASUREMENT  _IOW('f', 134, struct fsverity_measurement)
+
+#define FS_VERITY_ALG_SHA256           1
+
+struct fsverity_measurement {
+    __u16 digest_algorithm;
+    __u16 digest_size;
+    __u32 reserved1;
+    __u64 reserved2[3];
+    __u8 digest[];
 };
 
-struct fsverity_root_hash {
-    short root_hash_algorithm;
-    short flags;
-    __u8 reserved[4];
-    __u8 root_hash[64];
-};
-
-#define FS_IOC_MEASURE_FSVERITY        _IOW('f', 133, struct fsverity_root_hash)
-#define FS_IOC_SET_FSVERITY            _IOW('f', 134, struct fsverity_set)
-
-#define FSVERITY_FLAG_ENABLED          0x0001
 #endif
 
 binder::Status InstalldNativeService::installApkVerity(const std::string& filePath,
-        const ::android::base::unique_fd& verityInputAshmem) {
+        const ::android::base::unique_fd& verityInputAshmem, int32_t contentSize) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PATH(filePath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -2440,7 +2439,7 @@
     if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
         return ok();
     }
-#if DEBUG
+#ifndef NDEBUG
     ASSERT_PAGE_SIZE_4K();
 #endif
     // TODO: also check fsverity support in the current file system if compiled with DEBUG.
@@ -2449,15 +2448,14 @@
         return error("FD is not an ashmem");
     }
 
-    // TODO(71871109): Validate filePath.
     // 1. Seek to the next page boundary beyond the end of the file.
     ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY));
     if (wfd.get() < 0) {
-        return error("Failed to open " + filePath + ": " + strerror(errno));
+        return error("Failed to open " + filePath);
     }
     struct stat st;
     if (fstat(wfd.get(), &st) < 0) {
-        return error("Failed to stat " + filePath + ": " + strerror(errno));
+        return error("Failed to stat " + filePath);
     }
     // fsverity starts from the block boundary.
     off_t padding = kVerityPageSize - st.st_size % kVerityPageSize;
@@ -2465,38 +2463,51 @@
         padding = 0;
     }
     if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) {
-        return error("Failed to lseek " + filePath + ": " + strerror(errno));
+        return error("Failed to lseek " + filePath);
     }
 
-    // 2. Write everything in the ashmem to the file.
-    int size = ashmem_get_size_region(verityInputAshmem.get());
-    if (size < 0) {
-        return error("Failed to get ashmem size: " + std::to_string(size));
+    // 2. Write everything in the ashmem to the file.  Note that allocated
+    //    ashmem size is multiple of page size, which is different from the
+    //    actual content size.
+    int shmSize = ashmem_get_size_region(verityInputAshmem.get());
+    if (shmSize < 0) {
+        return error("Failed to get ashmem size: " + std::to_string(shmSize));
     }
-    void* data = mmap(NULL, size, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0);
-    if (data == MAP_FAILED) {
-        return error("Failed to mmap the ashmem: " + std::string(strerror(errno)));
+    if (contentSize < 0) {
+        return error("Invalid content size: " + std::to_string(contentSize));
     }
-    char* cursor = reinterpret_cast<char*>(data);
-    int remaining = size;
+    if (contentSize > shmSize) {
+        return error("Content size overflow: " + std::to_string(contentSize) + " > " +
+                     std::to_string(shmSize));
+    }
+    auto data = std::unique_ptr<void, std::function<void (void *)>>(
+        mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
+        [contentSize] (void* ptr) {
+          if (ptr != MAP_FAILED) {
+            munmap(ptr, contentSize);
+          }
+        });
+
+    if (data.get() == MAP_FAILED) {
+        return error("Failed to mmap the ashmem");
+    }
+    char* cursor = reinterpret_cast<char*>(data.get());
+    int remaining = contentSize;
     while (remaining > 0) {
         int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining));
         if (ret < 0) {
-            munmap(data, size);
             return error("Failed to write to " + filePath + " (" + std::to_string(remaining) +
-                         + "/" + std::to_string(size) + "): " + strerror(errno));
+                         + "/" + std::to_string(contentSize) + ")");
         }
         cursor += ret;
         remaining -= ret;
     }
-    munmap(data, size);
+    wfd.reset();
 
-    // 3. Enable fsverity. Once it's done, the file becomes immutable.
-    struct fsverity_set config;
-    config.offset = st.st_size;
-    config.flags = FSVERITY_FLAG_ENABLED;
-    if (ioctl(wfd.get(), FS_IOC_SET_FSVERITY, &config) < 0) {
-        return error("Failed to enable fsverity on " + filePath + ": " + strerror(errno));
+    // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable.
+    ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY));
+    if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
+        return error("Failed to enable fsverity on " + filePath);
     }
     return ok();
 }
@@ -2516,17 +2527,19 @@
                      std::to_string(expectedHash.size()));
     }
 
-    // TODO(71871109): Validate filePath.
     ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
     if (fd.get() < 0) {
         return error("Failed to open " + filePath + ": " + strerror(errno));
     }
 
-    struct fsverity_root_hash config;
-    memset(&config, 0, sizeof(config));
-    config.root_hash_algorithm = 0;  // SHA256
-    memcpy(config.root_hash, expectedHash.data(), std::min(sizeof(config.root_hash), kSha256Size));
-    if (ioctl(fd.get(), FS_IOC_MEASURE_FSVERITY, &config) < 0) {
+    unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size;
+    std::vector<char> buffer(buffer_size, 0);
+
+    fsverity_measurement* config = reinterpret_cast<fsverity_measurement*>(buffer.data());
+    config->digest_algorithm = FS_VERITY_ALG_SHA256;
+    config->digest_size = kSha256Size;
+    memcpy(config->digest, expectedHash.data(), kSha256Size);
+    if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) {
         // This includes an expected failure case with no FSVerity setup. It normally happens when
         // the apk does not contains the Merkle tree root hash.
         return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno));
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 2a31967..cebd3f9 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -123,7 +123,7 @@
     binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
             const std::unique_ptr<std::string>& outputPath);
     binder::Status installApkVerity(const std::string& filePath,
-            const ::android::base::unique_fd& verityInput);
+            const ::android::base::unique_fd& verityInput, int32_t contentSize);
     binder::Status assertFsverityRootHashMatches(const std::string& filePath,
             const std::vector<uint8_t>& expectedHash);
     binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 0c364bd..91e20b7 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -85,7 +85,8 @@
             @utf8InCpp String outputPath);
     void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
             @nullable @utf8InCpp String outputPath);
-    void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput);
+    void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput,
+            int contentSize);
     void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash);
 
     boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index b9e0139..8e393c0 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -280,7 +280,8 @@
             "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
             "the library and successfully fetched the passthrough implementation.");
     mImplementationsTable.setDescription(
-            "All available passthrough implementations (all -impl.so files)");
+            "All available passthrough implementations (all -impl.so files).\n"
+            "These may return subclasses through their respective HIDL_FETCH_I* functions.");
 }
 
 static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
@@ -377,8 +378,7 @@
                 }
                 if (findAndBumpVersion(hal, version)) {
                     if (&table != &mImplementationsTable) {
-                        hal->interfaces[interfaceName].name = interfaceName;
-                        hal->interfaces[interfaceName].instances.insert(instanceName);
+                        hal->insertLegacyInstance(interfaceName, instanceName);
                     }
                     hal->transportArch.arch |= arch;
                     done = true;
@@ -388,17 +388,16 @@
             if (done) {
                 continue; // to next TableEntry
             }
-            decltype(vintf::ManifestHal::interfaces) interfaces;
+            vintf::ManifestHal manifestHal{
+                    vintf::HalFormat::HIDL,
+                    std::string{fqName.package()},
+                    {version},
+                    {transport, arch},
+                    {}};
             if (&table != &mImplementationsTable) {
-                interfaces[interfaceName].name = interfaceName;
-                interfaces[interfaceName].instances.insert(instanceName);
+                manifestHal.insertLegacyInstance(interfaceName, instanceName);
             }
-            if (!manifest.add(vintf::ManifestHal{
-                    .format = vintf::HalFormat::HIDL,
-                    .name = fqName.package(),
-                    .versions = {version},
-                    .transportArch = {transport, arch},
-                    .interfaces = interfaces})) {
+            if (!manifest.add(std::move(manifestHal))) {
                 err() << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
             }
         }
@@ -407,7 +406,7 @@
          << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
          << INIT_VINTF_NOTES
          << "-->" << std::endl;
-    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_ONLY);
+    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_NO_FQNAME);
 }
 
 std::string ListCommand::INIT_VINTF_NOTES{
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 5a029d0..c2bf97e 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -85,6 +85,7 @@
     OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */
     OMX_IndexParamVideoVp9,                         /**< reference: OMX_VIDEO_PARAM_VP9TYPE */
     OMX_IndexParamVideoAndroidVp9Encoder,           /**< reference: OMX_VIDEO_PARAM_ANDROID_VP9ENCODERTYPE */
+    OMX_IndexParamVideoAndroidImageGrid,            /**< reference: OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE */
     OMX_IndexExtVideoEndUnused,
 
     /* Image & Video common configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index dc5cdab..9fd2fd2 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -89,6 +89,7 @@
     OMX_VIDEO_CodingVP9,        /**< Google VP9 */
     OMX_VIDEO_CodingHEVC,       /**< ITU H.265/HEVC */
     OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */
+    OMX_VIDEO_CodingImageHEIC,  /**< HEIF image encoded with HEVC */
     OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_VIDEO_CodingMax = 0x7FFFFFFF
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index c102564..bbf157b 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -213,6 +213,7 @@
     OMX_VIDEO_HEVCProfileUnknown      = 0x0,
     OMX_VIDEO_HEVCProfileMain         = 0x1,
     OMX_VIDEO_HEVCProfileMain10       = 0x2,
+    OMX_VIDEO_HEVCProfileMainStill    = 0x4,
     // Main10 profile with HDR SEI support.
     OMX_VIDEO_HEVCProfileMain10HDR10  = 0x1000,
     OMX_VIDEO_HEVCProfileMax          = 0x7FFFFFFF
@@ -421,6 +422,49 @@
     OMX_U32 nBitrateRatios[OMX_VIDEO_ANDROID_MAXTEMPORALLAYERS];
 } OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE;
 
+/**
+ * Android specific param for specifying image grid layout information for image encoding
+ * use cases, corresponding to index OMX_IndexParamVideoAndroidImageGrid.
+ *
+ * OMX_VIDEO_CodingImageHEIC encoders must handle this param type. When this param is set
+ * on the component with bEnabled set to true, nTileWidth, nTileHeight, nGridRows,
+ * nGridCols indicates the desired grid config by the client. The component can use this
+ * as a heuristic, and is free to choose any suitable grid configs. The client shall
+ * always get the actual from the component after the param is set. Encoder will receive
+ * each input image in full, and shall encode it into tiles in row-major, top-row first,
+ * left-to-right order, and send each encoded tile in a separate output buffer. All output
+ * buffers for the same input buffer shall carry the same timestamp as the input buffer.
+ * If the input buffer is marked EOS, the EOS should only appear on the last output buffer
+ * for that input buffer.
+ *
+ * OMX_VIDEO_CodingHEVC encoders might also receive this param when it's used for image
+ * encoding, although in this case the param only serves as a hint. The encoder will
+ * receive the input image tiles in row-major, top-row first, left-to-right order.
+ * The grid config can be used for quality control, or optimizations.
+ *
+ * If this param is not set, the component shall assume that grid option is disabled.
+ *
+ *  nSize                      : Size of the structure in bytes
+ *  nVersion                   : OMX specification version information
+ *  nPortIndex                 : Port that this structure applies to (output port for encoders)
+ *  bEnabled                   : Whether grid is enabled. If true, the other parameters
+ *                               specifies the grid config; otherwise they shall be ignored.
+ *  nTileWidth                 : Width of each tile.
+ *  nTileHeight                : Height of each tile.
+ *  nGridRows                  : Number of rows in the grid.
+ *  nGridCols                  : Number of cols in the grid.
+ */
+typedef struct OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnabled;
+    OMX_U32 nTileWidth;
+    OMX_U32 nTileHeight;
+    OMX_U32 nGridRows;
+    OMX_U32 nGridCols;
+} OMX_VIDEO_PARAM_ANDROID_IMAGEGRIDTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h
index 80741c0..b36728e 100644
--- a/libs/arect/include/android/rect.h
+++ b/libs/arect/include/android/rect.h
@@ -33,23 +33,26 @@
 #endif
 
 /**
- * {@link ARect} is a struct that represents a rectangular window area.
+ * Rectangular window area.
  *
- * It is used with {@link
- * ANativeActivityCallbacks::onContentRectChanged} event callback and
- * ANativeWindow_lock() function.
+ * This is the NDK equivalent of the android.graphics.Rect class in Java. It is
+ * used with {@link ANativeActivityCallbacks::onContentRectChanged} event
+ * callback and the ANativeWindow_lock() function.
+ *
+ * In a valid ARect, left <= right and top <= bottom. ARect with left=0, top=10,
+ * right=1, bottom=11 contains only one pixel at x=0, y=10.
  */
 typedef struct ARect {
 #ifdef __cplusplus
     typedef int32_t value_type;
 #endif
-    /** left position */
+    /// Minimum X coordinate of the rectangle.
     int32_t left;
-    /** top position */
+    /// Minimum Y coordinate of the rectangle.
     int32_t top;
-    /** left position */
+    /// Maximum X coordinate of the rectangle.
     int32_t right;
-    /** bottom position */
+    /// Maximum Y coordinate of the rectangle.
     int32_t bottom;
 } ARect;
 
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index e1cc5da..2728f35 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -80,4 +80,29 @@
     }
 }
 
+bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return service->isUidActive(uid, callingPackage);
+    }
+    return false;
+}
+
+status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return IInterface::asBinder(service)->linkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        return IInterface::asBinder(service)->unlinkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index b7a5fd9..428db4d 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -78,6 +78,18 @@
          data.writeStrongBinder(IInterface::asBinder(observer));
          remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
     }
+
+    virtual bool isUidActive(const uid_t uid, const String16& callingPackage)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeInt32(uid);
+         data.writeString16(callingPackage);
+         remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
+         // fail on exception
+         if (reply.readExceptionCode() != 0) return false;
+         return reply.readInt32() == 1;
+    }
 };
 
 // ------------------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 408c428..3090cae 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -50,6 +50,10 @@
                              const int32_t cutpoint,
                              const String16& callingPackage);
     void unregisterUidObserver(const sp<IUidObserver>& observer);
+    bool isUidActive(const uid_t uid, const String16& callingPackage);
+
+    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+    status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
 
 private:
     Mutex mLock;
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index bac2a99..6607c0e 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -35,11 +35,13 @@
                                      const int32_t cutpoint,
                                      const String16& callingPackage) = 0;
     virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
+    virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
 
     enum {
         OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         REGISTER_UID_OBSERVER_TRANSACTION,
-        UNREGISTER_UID_OBSERVER_TRANSACTION
+        UNREGISTER_UID_OBSERVER_TRANSACTION,
+        IS_UID_ACTIVE_TRANSACTION
     };
 };
 
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a1a0928..2768ad8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -122,6 +122,7 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.common@1.1",
         "libsync",
         "libbinder",
         "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
@@ -154,6 +155,7 @@
         "libui",
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.common@1.1",
     ],
 
     export_header_lib_headers: [
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 788a6eb..885efec 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -984,7 +984,8 @@
     }
 
     if (mCurrentFence->isValid()) {
-        if (SyncFeatures::getInstance().useWaitSync()) {
+        if (SyncFeatures::getInstance().useWaitSync() &&
+            SyncFeatures::getInstance().useNativeFenceSync()) {
             // Create an EGLSyncKHR from the current fence.
             int fenceFd = mCurrentFence->dup();
             if (fenceFd == -1) {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5de84ec..e22bc70 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -43,6 +43,8 @@
 
 namespace android {
 
+using ui::ColorMode;
+
 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
 {
 public:
@@ -132,12 +134,13 @@
 
     virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
                                    sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
-                                   float frameScale) {
+                                   float frameScale, bool childrenOnly) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(layerHandleBinder);
         data.write(sourceCrop);
         data.writeFloat(frameScale);
+        data.writeBool(childrenOnly);
         status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
 
         if (err != NO_ERROR) {
@@ -349,7 +352,7 @@
     }
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes) {
+            Vector<ColorMode>* outColorModes) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -372,34 +375,34 @@
             outColorModes->clear();
             outColorModes->resize(numModes);
             for (size_t i = 0; i < numModes; ++i) {
-                outColorModes->replaceAt(static_cast<android_color_mode_t>(reply.readInt32()), i);
+                outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i);
             }
         }
         return result;
     }
 
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) {
+    virtual ColorMode getActiveColorMode(const sp<IBinder>& display) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
         result = data.writeStrongBinder(display);
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
         result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply);
         if (result != NO_ERROR) {
             ALOGE("getActiveColorMode failed to transact: %d", result);
-            return static_cast<android_color_mode_t>(result);
+            return static_cast<ColorMode>(result);
         }
-        return static_cast<android_color_mode_t>(reply.readInt32());
+        return static_cast<ColorMode>(reply.readInt32());
     }
 
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            android_color_mode_t colorMode) {
+            ColorMode colorMode) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
@@ -411,7 +414,7 @@
             ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result);
             return result;
         }
-        result = data.writeInt32(colorMode);
+        result = data.writeInt32(static_cast<int32_t>(colorMode));
         if (result != NO_ERROR) {
             ALOGE("setActiveColorMode failed to writeInt32: %d", result);
             return result;
@@ -629,8 +632,10 @@
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             float frameScale = data.readFloat();
+            bool childrenOnly = data.readBool();
 
-            status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale);
+            status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
+                                         childrenOnly);
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
@@ -736,7 +741,7 @@
         }
         case GET_DISPLAY_COLOR_MODES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Vector<android_color_mode_t> colorModes;
+            Vector<ColorMode> colorModes;
             sp<IBinder> display = nullptr;
             status_t result = data.readStrongBinder(&display);
             if (result != NO_ERROR) {
@@ -748,7 +753,7 @@
             if (result == NO_ERROR) {
                 reply->writeUint32(static_cast<uint32_t>(colorModes.size()));
                 for (size_t i = 0; i < colorModes.size(); ++i) {
-                    reply->writeInt32(colorModes[i]);
+                    reply->writeInt32(static_cast<int32_t>(colorModes[i]));
                 }
             }
             return NO_ERROR;
@@ -761,7 +766,7 @@
                 ALOGE("getActiveColorMode failed to readStrongBinder: %d", result);
                 return result;
             }
-            android_color_mode_t colorMode = getActiveColorMode(display);
+            ColorMode colorMode = getActiveColorMode(display);
             result = reply->writeInt32(static_cast<int32_t>(colorMode));
             return result;
         }
@@ -780,7 +785,7 @@
                 return result;
             }
             result = setActiveColorMode(display,
-                    static_cast<android_color_mode_t>(colorModeInt));
+                    static_cast<ColorMode>(colorModeInt));
             result = reply->writeInt32(result);
             return result;
         }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 679f44b..a6890ee 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -47,8 +47,8 @@
     ~BpSurfaceComposerClient() override;
 
     status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
-                           uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
-                           uint32_t ownerUid, sp<IBinder>* handle,
+                           uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
+                           int32_t ownerUid, sp<IBinder>* handle,
                            sp<IGraphicBufferProducer>* gbp) override {
         return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
                                                                             name, width, height,
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e08d6b0..339bd0f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -44,6 +44,9 @@
 
 namespace android {
 
+using ui::ColorMode;
+using ui::Dataspace;
+
 Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
       : mGraphicBufferProducer(bufferProducer),
         mCrop(Rect::EMPTY_RECT),
@@ -78,7 +81,7 @@
     mReqFormat = 0;
     mReqUsage = 0;
     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
-    mDataSpace = HAL_DATASPACE_UNKNOWN;
+    mDataSpace = Dataspace::UNKNOWN;
     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
     mTransform = 0;
     mStickyTransform = 0;
@@ -326,7 +329,7 @@
 
     sp<IBinder> display(
         composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    Vector<android_color_mode_t> colorModes;
+    Vector<ColorMode> colorModes;
     status_t err =
         composerService()->getDisplayColorModes(display, &colorModes);
 
@@ -338,11 +341,11 @@
                 &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
     *supported = false;
-    for (android_color_mode_t colorMode : colorModes) {
+    for (ColorMode colorMode : colorModes) {
         switch (colorMode) {
-            case HAL_COLOR_MODE_DISPLAY_P3:
-            case HAL_COLOR_MODE_ADOBE_RGB:
-            case HAL_COLOR_MODE_DCI_P3:
+            case ColorMode::DISPLAY_P3:
+            case ColorMode::ADOBE_RGB:
+            case ColorMode::DCI_P3:
                 if (wideColorBoardConfig) {
                     *supported = true;
                 }
@@ -664,8 +667,9 @@
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
     IGraphicBufferProducer::QueueBufferOutput output;
     IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
-            mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
-            fence, mStickyTransform, mEnableFrameTimestamps);
+            static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
+            mTransform ^ mStickyTransform, fence, mStickyTransform,
+            mEnableFrameTimestamps);
 
     // we should send HDR metadata as needed if this becomes a bottleneck
     input.setHdrMetadata(mHdrMetadata);
@@ -1096,8 +1100,7 @@
 }
 
 int Surface::dispatchSetBuffersDataSpace(va_list args) {
-    android_dataspace dataspace =
-            static_cast<android_dataspace>(va_arg(args, int));
+    Dataspace dataspace = static_cast<Dataspace>(va_arg(args, int));
     return setBuffersDataSpace(dataspace);
 }
 
@@ -1529,7 +1532,7 @@
     return NO_ERROR;
 }
 
-int Surface::setBuffersDataSpace(android_dataspace dataSpace)
+int Surface::setBuffersDataSpace(Dataspace dataSpace)
 {
     ALOGV("Surface::setBuffersDataSpace");
     Mutex::Autolock lock(mMutex);
@@ -1561,7 +1564,7 @@
     return NO_ERROR;
 }
 
-android_dataspace_t Surface::getBuffersDataSpace() {
+Dataspace Surface::getBuffersDataSpace() {
     ALOGV("Surface::getBuffersDataSpace");
     Mutex::Autolock lock(mMutex);
     return mDataSpace;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 92a24ad..bbf681e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -43,6 +43,8 @@
 #include <private/gui/ComposerService.h>
 
 namespace android {
+
+using ui::ColorMode;
 // ---------------------------------------------------------------------------
 
 ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
@@ -609,10 +611,28 @@
         PixelFormat format,
         uint32_t flags,
         SurfaceControl* parent,
-        uint32_t windowType,
-        uint32_t ownerUid)
+        int32_t windowType,
+        int32_t ownerUid)
+{
+    sp<SurfaceControl> s;
+    createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid);
+    return s;
+}
+
+status_t SurfaceComposerClient::createSurfaceChecked(
+        const String8& name,
+        uint32_t w,
+        uint32_t h,
+        PixelFormat format,
+        sp<SurfaceControl>* outSurface,
+        uint32_t flags,
+        SurfaceControl* parent,
+        int32_t windowType,
+        int32_t ownerUid)
 {
     sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
     if (mStatus == NO_ERROR) {
         sp<IBinder> handle;
         sp<IBinder> parentHandle;
@@ -621,14 +641,14 @@
         if (parent != nullptr) {
             parentHandle = parent->getHandle();
         }
-        status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle,
+        err = mClient->createSurface(name, w, h, format, flags, parentHandle,
                 windowType, ownerUid, &handle, &gbp);
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            sur = new SurfaceControl(this, handle, gbp, true /* owned */);
+            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
         }
     }
-    return sur;
+    return err;
 }
 
 status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
@@ -698,16 +718,16 @@
 }
 
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<android_color_mode_t>* outColorModes) {
+        Vector<ColorMode>* outColorModes) {
     return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
 }
 
-android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
+ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveColorMode(display);
 }
 
 status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display,
-        android_color_mode_t colorMode) {
+        ColorMode colorMode) {
     return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
 }
 
@@ -751,7 +771,17 @@
                                          float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
-    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale);
+    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+                                    false /* childrenOnly */);
+    return ret;
+}
+
+status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                              float frameScale, sp<GraphicBuffer>* outBuffer) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
+                                    true /* childrenOnly */);
     return ret;
 }
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e26e332..3591090 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -30,6 +30,7 @@
 #include <ui/FrameStats.h>
 #include <ui/PixelFormat.h>
 #include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
 
 #include <vector>
 
@@ -160,10 +161,10 @@
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0;
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes) = 0;
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) = 0;
+            Vector<ui::ColorMode>* outColorModes) = 0;
+    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
-            android_color_mode_t colorMode) = 0;
+            ui::ColorMode colorMode) = 0;
 
     /* Capture the specified screen. requires READ_FRAME_BUFFER permission
      * This function will fail if there is a secure window on screen.
@@ -173,9 +174,12 @@
                                    int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
                                    Rotation rotation = eRotateNone) = 0;
 
+    /**
+     * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+     */
     virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
                                    sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
-                                   float frameScale = 1.0) = 0;
+                                   float frameScale = 1.0, bool childrenOnly = false) = 0;
 
     /* Clears the frame statistics for animations.
      *
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index d5bbef2..8dfc99a 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -49,8 +49,8 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                                   uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
-                                   uint32_t ownerUid, sp<IBinder>* handle,
+                                   uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
+                                   int32_t ownerUid, sp<IBinder>* handle,
                                    sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 641d62c..9aeafae 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -22,6 +22,7 @@
 #include <gui/IGraphicBufferProducer.h>
 
 #include <ui/ANativeObjectBase.h>
+#include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 
 #include <utils/Condition.h>
@@ -245,7 +246,7 @@
     virtual int setBuffersTransform(uint32_t transform);
     virtual int setBuffersStickyTransform(uint32_t transform);
     virtual int setBuffersTimestamp(int64_t timestamp);
-    virtual int setBuffersDataSpace(android_dataspace dataSpace);
+    virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
     virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
     virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
     virtual int setCrop(Rect const* rect);
@@ -286,7 +287,7 @@
     // detachNextBuffer, or attachBuffer call.
     status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
 
-    android_dataspace_t getBuffersDataSpace();
+    ui::Dataspace getBuffersDataSpace();
 
     static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer);
 
@@ -340,9 +341,9 @@
     int64_t mTimestamp;
 
     // mDataSpace is the buffer dataSpace that will be used for the next buffer
-    // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which
+    // queue operation. It defaults to Dataspace::UNKNOWN, which
     // means that the buffer contains some type of color data.
-    android_dataspace mDataSpace;
+    ui::Dataspace mDataSpace;
 
     // mHdrMetadata is the HDR metadata that will be used for the next buffer
     // queue operation.  There is no HDR metadata by default.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 3fe6635..ffc22f6 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -29,6 +29,7 @@
 #include <utils/threads.h>
 
 #include <ui/FrameStats.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
@@ -88,13 +89,14 @@
 
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* outColorModes);
+            Vector<ui::ColorMode>* outColorModes);
 
     // Gets the active color mode for the given display
-    static android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
+    static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
 
     // Sets the active color mode for the given display
-    static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+    static status_t setActiveColorMode(const sp<IBinder>& display,
+            ui::ColorMode colorMode);
 
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
@@ -110,8 +112,20 @@
             PixelFormat format, // pixel-format desired
             uint32_t flags = 0, // usage flags
             SurfaceControl* parent = nullptr, // parent
-            uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            uint32_t ownerUid = 0 // UID of the task
+            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1 // UID of the task
+    );
+
+    status_t createSurfaceChecked(
+            const String8& name,// name of the surface
+            uint32_t w,         // width in pixel
+            uint32_t h,         // height in pixel
+            PixelFormat format, // pixel-format desired
+            sp<SurfaceControl>* outSurface,
+            uint32_t flags = 0, // usage flags
+            SurfaceControl* parent = nullptr, // parent
+            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
+            int32_t ownerUid = -1 // UID of the task
     );
 
     //! Create a virtual display
@@ -297,8 +311,10 @@
                             uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
                             bool useIdentityTransform, uint32_t rotation,
                             sp<GraphicBuffer>* outBuffer);
-    static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float fameScale,
+    static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
                                   sp<GraphicBuffer>* outBuffer);
+    static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                       float frameScale, sp<GraphicBuffer>* outBuffer);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8060b6e..2c02ba6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -42,6 +42,7 @@
 // retrieve wide-color and hdr settings from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ui::ColorMode;
 
 using Transaction = SurfaceComposerClient::Transaction;
 
@@ -58,7 +59,6 @@
 
 class SurfaceTest : public ::testing::Test {
 protected:
-
     SurfaceTest() {
         ProcessState::self()->startThreadPool();
     }
@@ -93,6 +93,16 @@
     sp<SurfaceControl> mSurfaceControl;
 };
 
+TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) {
+    mComposerClient->dispose();
+    ASSERT_EQ(NO_INIT, mComposerClient->initCheck());
+
+    sp<SurfaceControl> sc;
+    status_t err = mComposerClient->createSurfaceChecked(
+            String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0);
+    ASSERT_EQ(NO_INIT, err);
+}
+
 TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
     sp<ANativeWindow> anw(mSurface);
     int result = -123;
@@ -577,15 +587,15 @@
         return NO_ERROR;
     }
     status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
-            Vector<android_color_mode_t>* /*outColorModes*/) override {
+            Vector<ColorMode>* /*outColorModes*/) override {
         return NO_ERROR;
     }
-    android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/)
+    ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
             override {
-        return HAL_COLOR_MODE_NATIVE;
+        return ColorMode::NATIVE;
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
-            android_color_mode_t /*colorMode*/) override { return NO_ERROR; }
+        ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureScreen(const sp<IBinder>& /*display*/,
             sp<GraphicBuffer>* /*outBuffer*/,
             Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
@@ -593,8 +603,8 @@
             bool /*useIdentityTransform*/,
             Rotation /*rotation*/) override { return NO_ERROR; }
     virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
-                                   sp<GraphicBuffer>* /*outBuffer*/,
-                                   const Rect& /*sourceCrop*/, float /*frameScale*/) override {
+                                   sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
+                                   float /*frameScale*/, bool /*childrenOnly*/) override {
         return NO_ERROR;
     }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index a2712b4..f37ef28 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -343,14 +343,6 @@
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
             "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_YCBCR_422_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_YCBCR_444_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_FLEX_RGB_888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8,
-            "HAL and AHardwareBuffer pixel format don't match");
-    static_assert(HAL_PIXEL_FORMAT_FLEX_RGBA_8888 == AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8,
-            "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
             "HAL and AHardwareBuffer pixel format don't match");
     static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
@@ -383,10 +375,6 @@
         case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
         case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
         case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444:
-        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8:
-        case AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index a477bf2..cc67aca 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -41,9 +41,11 @@
     AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM           = 1,
 
     /**
+     * 32 bits per pixel, 8 bits per channel format where alpha values are
+     * ignored (always opaque).
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
-     *   OpenGL ES: GL_RGBA8
+     *   OpenGL ES: GL_RGB8
      */
     AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM           = 2,
 
@@ -124,40 +126,49 @@
     AHARDWAREBUFFER_FORMAT_S8_UINT                  = 0x35,
 };
 
+/**
+ * Buffer usage flags, specifying how the buffer will be accessed.
+ */
 enum {
-    /* The buffer will never be read by the CPU */
+    /// The buffer will never be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_NEVER        = 0UL,
-    /* The buffer will sometimes be read by the CPU */
+    /// The buffer will sometimes be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_RARELY       = 2UL,
-    /* The buffer will often be read by the CPU */
+    /// The buffer will often be read by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN        = 3UL,
-    /* CPU read value mask */
+    /// CPU read value mask.
     AHARDWAREBUFFER_USAGE_CPU_READ_MASK         = 0xFUL,
 
-    /* The buffer will never be written by the CPU */
+    /// The buffer will never be written by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER       = 0UL << 4,
-    /* The buffer will sometimes be written to by the CPU */
+    /// The buffer will sometimes be written to by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY      = 2UL << 4,
-    /* The buffer will often be written to by the CPU */
+    /// The buffer will often be written to by the CPU.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN       = 3UL << 4,
-    /* CPU write value mask */
+    /// CPU write value mask.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
 
-    /* The buffer will be read from by the GPU */
+    /// The buffer will be read from by the GPU as a texture.
     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
-    /* The buffer will be written to by the GPU */
+    /**
+     * The buffer will be written to by the GPU as a framebuffer attachment.
+     * Note that the name of this flag is somewhat misleading: it does not imply
+     * that the buffer contains a color format. A buffer with depth or stencil
+     * format that will be used as a framebuffer attachment should also have
+     * this flag.
+     */
     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = 1UL << 9,
-    /* The buffer must not be used outside of a protected hardware path */
+    /// The buffer must not be used outside of a protected hardware path.
     AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
-    /* The buffer will be read by a hardware video encoder */
+    /// The buffer will be read by a hardware video encoder.
     AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
-    /* The buffer will be used for sensor direct data */
+    /// The buffer will be used for direct writes from sensors.
     AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
-    /* The buffer will be used as a shader storage or uniform buffer object */
+    /// The buffer will be used as a shader storage or uniform buffer object.
     AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
-    /* The buffer will be used as a cube map texture */
+    /// The buffer will be used as a cube map texture.
     AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
-    /* The buffer contains a complete mipmap hierarchy */
+    /// The buffer contains a complete mipmap hierarchy.
     AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
 
     AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
@@ -182,15 +193,19 @@
     AHARDWAREBUFFER_USAGE_VENDOR_19 = 1ULL << 63,
 };
 
+/**
+ * Buffer description. Used for allocating new buffers and querying parameters
+ * of existing ones.
+ */
 typedef struct AHardwareBuffer_Desc {
-    uint32_t    width;      // width in pixels
-    uint32_t    height;     // height in pixels
-    uint32_t    layers;     // number of images
-    uint32_t    format;     // One of AHARDWAREBUFFER_FORMAT_*
-    uint64_t    usage;      // Combination of AHARDWAREBUFFER_USAGE_*
-    uint32_t    stride;     // Stride in pixels, ignored for AHardwareBuffer_allocate()
-    uint32_t    rfu0;       // Initialize to zero, reserved for future use
-    uint64_t    rfu1;       // Initialize to zero, reserved for future use
+    uint32_t    width;      ///< Width in pixels.
+    uint32_t    height;     ///< Height in pixels.
+    uint32_t    layers;     ///< Number of images in an image array.
+    uint32_t    format;     ///< One of AHARDWAREBUFFER_FORMAT_*
+    uint64_t    usage;      ///< Combination of AHARDWAREBUFFER_USAGE_*
+    uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
+    uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
+    uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
 typedef struct AHardwareBuffer AHardwareBuffer;
@@ -199,8 +214,8 @@
  * Allocates a buffer that backs an AHardwareBuffer using the passed
  * AHardwareBuffer_Desc.
  *
- * Returns NO_ERROR on success, or an error number of the allocation fails for
- * any reason.
+ * \return NO_ERROR on success, or an error number of the allocation fails for
+ * any reason. The returned buffer has a reference count of 1.
  */
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
         AHardwareBuffer** outBuffer);
@@ -223,7 +238,7 @@
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
         AHardwareBuffer_Desc* outDesc);
 
-/*
+/**
  * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
  * passed.  This call may block if the hardware needs to finish rendering or if
  * CPU caches need to be synchronized, or possibly for other implementation-
@@ -231,16 +246,16 @@
  * descriptor that will be signaled when the buffer is locked, otherwise the
  * caller will block until the buffer is available.
  *
- * If rect is not NULL, the caller promises to modify only data in the area
+ * If \a rect is not NULL, the caller promises to modify only data in the area
  * specified by rect. If rect is NULL, the caller may modify the contents of the
  * entire buffer.
  *
  * The content of the buffer outside of the specified rect is NOT modified
  * by this call.
  *
- * The buffer usage may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, then
- * outVirtualAddress is filled with the address of the buffer in virtual memory,
- * otherwise this function will fail.
+ * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
+ * then outVirtualAddress is filled with the address of the buffer in virtual
+ * memory.
  *
  * THREADING CONSIDERATIONS:
  *
@@ -252,38 +267,38 @@
  * may return an error or leave the buffer's content into an indeterminate
  * state.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL or if the usage
+ * \return NO_ERROR on success, BAD_VALUE if \a buffer is NULL or if the usage
  * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
  * number of the lock fails for any reason.
  */
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress);
 
-/*
+/**
  * Unlock the AHardwareBuffer; must be called after all changes to the buffer
  * are completed by the caller. If fence is not NULL then it will be set to a
  * file descriptor that is signaled when all pending work on the buffer is
  * completed. The caller is responsible for closing the fence when it is no
  * longer needed.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return NO_ERROR on success, BAD_VALUE if \a buffer is NULL, or an error
+ * number if the unlock fails for any reason.
  */
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence);
 
-/*
+/**
  * Send the AHardwareBuffer to an AF_UNIX socket.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return NO_ERROR on success, BAD_VALUE if \a buffer is NULL, or an error
+ * number if the operation fails for any reason.
  */
 int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
 
-/*
+/**
  * Receive the AHardwareBuffer from an AF_UNIX socket.
  *
- * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
- * number of the lock fails for any reason.
+ * \return NO_ERROR on success, BAD_VALUE if \a outBuffer is NULL, or an error
+ * number if the operation fails for any reason.
  */
 int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index f2d6f7a..d5e5e9d 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -85,23 +85,23 @@
  * A pointer can be obtained using {@link ANativeWindow_lock()}.
  */
 typedef struct ANativeWindow_Buffer {
-    // The number of pixels that are show horizontally.
+    /// The number of pixels that are shown horizontally.
     int32_t width;
 
-    // The number of pixels that are shown vertically.
+    /// The number of pixels that are shown vertically.
     int32_t height;
 
-    // The number of *pixels* that a line in the buffer takes in
-    // memory. This may be >= width.
+    /// The number of *pixels* that a line in the buffer takes in
+    /// memory. This may be >= width.
     int32_t stride;
 
-    // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+    /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
     int32_t format;
 
-    // The actual bits.
+    /// The actual bits.
     void* bits;
 
-    // Do not touch.
+    /// Do not touch.
     uint32_t reserved[6];
 } ANativeWindow_Buffer;
 
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 802edcc..7a4b31f 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -53,14 +53,6 @@
     AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED   = 0x22,
     /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
     AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_422_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_422             = 0x27,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_444_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_444             = 0x28,
-    /* same as HAL_PIXEL_FORMAT_FLEX_RGB_888 */
-    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8              = 0x29,
-    /* same as HAL_PIXEL_FORMAT_FLEX_RGBA_8888 */
-    AHARDWAREBUFFER_FORMAT_FLEX_R8G8B8A8            = 0x2A,
     /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
     AHARDWAREBUFFER_FORMAT_YCbCr_422_SP             = 0x10,
     /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index f71f814..e477a83 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -83,6 +83,7 @@
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
+        "libpdx_default_transport",
         "libsync",
         "libutils",
         "libutilscallstack",
@@ -99,10 +100,9 @@
         "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
+        "libui_headers",
     ],
 
-    export_include_dirs: ["include"],
-
     export_static_lib_headers: [
         "libarect",
         "libmath",
@@ -112,6 +112,7 @@
         "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
+        "libui_headers",
     ],
 }
 
@@ -119,6 +120,11 @@
     name: "libui_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    target: {
+        vendor: {
+            override_export_include_dirs: ["include_vndk"],
+        },
+    },
 }
 
 subdirs = [
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 17ebf80..58fed84 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -22,6 +22,7 @@
 #include <string>
 
 using android::base::StringPrintf;
+using android::ui::ColorMode;
 
 std::string decodeStandard(android_dataspace dataspace) {
     const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
@@ -197,42 +198,69 @@
                                        decodeRange(dataspace).c_str());
 }
 
-std::string decodeColorMode(android_color_mode colorMode) {
+std::string decodeColorMode(ColorMode colorMode) {
     switch (colorMode) {
-        case HAL_COLOR_MODE_NATIVE:
-            return std::string("HAL_COLOR_MODE_NATIVE");
+        case ColorMode::NATIVE:
+            return std::string("ColorMode::NATIVE");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_625:
-            return std::string("HAL_COLOR_MODE_BT601_625");
+        case ColorMode::STANDARD_BT601_625:
+            return std::string("ColorMode::BT601_625");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
-            return std::string("HAL_COLOR_MODE_BT601_625_UNADJUSTED");
+        case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+            return std::string("ColorMode::BT601_625_UNADJUSTED");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_525:
-            return std::string("HAL_COLOR_MODE_BT601_525");
+        case ColorMode::STANDARD_BT601_525:
+            return std::string("ColorMode::BT601_525");
 
-        case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
-            return std::string("HAL_COLOR_MODE_BT601_525_UNADJUSTED");
+        case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+            return std::string("ColorMode::BT601_525_UNADJUSTED");
 
-        case HAL_COLOR_MODE_STANDARD_BT709:
-            return std::string("HAL_COLOR_MODE_BT709");
+        case ColorMode::STANDARD_BT709:
+            return std::string("ColorMode::BT709");
 
-        case HAL_COLOR_MODE_DCI_P3:
-            return std::string("HAL_COLOR_MODE_DCI_P3");
+        case ColorMode::DCI_P3:
+            return std::string("ColorMode::DCI_P3");
 
-        case HAL_COLOR_MODE_SRGB:
-            return std::string("HAL_COLOR_MODE_SRGB");
+        case ColorMode::SRGB:
+            return std::string("ColorMode::SRGB");
 
-        case HAL_COLOR_MODE_ADOBE_RGB:
-            return std::string("HAL_COLOR_MODE_ADOBE_RGB");
+        case ColorMode::ADOBE_RGB:
+            return std::string("ColorMode::ADOBE_RGB");
 
-        case HAL_COLOR_MODE_DISPLAY_P3:
-            return std::string("HAL_COLOR_MODE_DISPLAY_P3");
+        case ColorMode::DISPLAY_P3:
+            return std::string("ColorMode::DISPLAY_P3");
     }
 
     return android::base::StringPrintf("Unknown color mode %d", colorMode);
 }
 
+std::string decodeColorTransform(android_color_transform colorTransform) {
+    switch (colorTransform) {
+        case HAL_COLOR_TRANSFORM_IDENTITY:
+            return std::string("Identity");
+
+        case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+            return std::string("Arbitrary matrix");
+
+        case HAL_COLOR_TRANSFORM_VALUE_INVERSE:
+            return std::string("Inverse value");
+
+        case HAL_COLOR_TRANSFORM_GRAYSCALE:
+            return std::string("Grayscale");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA:
+            return std::string("Correct protanopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA:
+            return std::string("Correct deuteranopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA:
+            return std::string("Correct tritanopia");
+    }
+
+    return android::base::StringPrintf("Unknown color transform %d", colorTransform);
+}
+
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
 // (Could use a table of prefab String8 objects.)
 std::string decodePixelFormat(android::PixelFormat format) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 4ed2aa4..254038b 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -22,6 +22,7 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
+#include <ui/DetachedBufferHandle.h>
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
@@ -486,6 +487,24 @@
     return NO_ERROR;
 }
 
+bool GraphicBuffer::isDetachedBuffer() const {
+    return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
+}
+
+status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
+    if (isDetachedBuffer()) {
+        ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
+              "GraphicBuffer. Replacing the old one.");
+    }
+
+    mDetachedBufferHandle = std::move(channel);
+    return NO_ERROR;
+}
+
+std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
+    return std::move(mDetachedBufferHandle);
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index dad9446..5e5df43 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <system/graphics.h>
+#include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <string>
@@ -29,6 +29,7 @@
 std::string decodeTransfer(android_dataspace dataspace);
 std::string decodeRange(android_dataspace dataspace);
 std::string dataspaceDetails(android_dataspace dataspace);
-std::string decodeColorMode(android_color_mode colormode);
+std::string decodeColorMode(android::ui::ColorMode colormode);
+std::string decodeColorTransform(android_color_transform colorTransform);
 std::string decodePixelFormat(android::PixelFormat format);
 std::string to_string(const android::Rect& rect);
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
new file mode 100644
index 0000000..f3c328d
--- /dev/null
+++ b/libs/ui/include/ui/DetachedBufferHandle.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
+#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
+
+#include <pdx/channel_handle.h>
+
+#include <memory>
+
+namespace android {
+
+// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
+// created. Current implementation assumes that the underlying transport is using libpdx (thus
+// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
+// backend if ever needed.
+class DetachedBufferHandle {
+public:
+    static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
+        return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
+    }
+
+    // Accessors to get or take the internal pdx::LocalChannelHandle.
+    pdx::LocalChannelHandle& handle() { return mHandle; }
+    const pdx::LocalChannelHandle& handle() const { return mHandle; }
+
+    // Returns whether the DetachedBufferHandle holds a BufferHub channel.
+    bool isValid() const { return mHandle.valid(); }
+
+private:
+    // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
+    explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
+
+    pdx::LocalChannelHandle mHandle;
+};
+
+} // namespace android
+
+#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index e794462..cc38982 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -34,6 +34,7 @@
 
 namespace android {
 
+class DetachedBufferHandle;
 class GraphicBufferMapper;
 
 // ===========================================================================
@@ -190,6 +191,11 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
+    // Sets and takes DetachedBuffer. Should only be called from BufferHub.
+    bool isDetachedBuffer() const;
+    status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
+    std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
+
 private:
     ~GraphicBuffer();
 
@@ -240,6 +246,17 @@
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
+
+    // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
+    // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
+    // there are three different modes:
+    // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
+    //    invalid.
+    // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
+    //    set. In this mode, mDetachedBufferHandle must be valid.
+    // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
+    //    set. In this mode, mDetachedBufferHandle must be invalid.
+    std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
new file mode 100644
index 0000000..92a5519
--- /dev/null
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <system/graphics.h>
+
+// android::ui::* in this header file will alias different types as
+// the HIDL interface is updated.
+namespace android {
+namespace ui {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/include_vndk/ui/ANativeObjectBase.h b/libs/ui/include_vndk/ui/ANativeObjectBase.h
new file mode 120000
index 0000000..4dab8d8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ANativeObjectBase.h
@@ -0,0 +1 @@
+../../include/ui/ANativeObjectBase.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/BufferQueueDefs.h b/libs/ui/include_vndk/ui/BufferQueueDefs.h
new file mode 120000
index 0000000..c886ed8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/BufferQueueDefs.h
@@ -0,0 +1 @@
+../../include/ui/BufferQueueDefs.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/ColorSpace.h b/libs/ui/include_vndk/ui/ColorSpace.h
new file mode 120000
index 0000000..ddf70d5
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ColorSpace.h
@@ -0,0 +1 @@
+../../include/ui/ColorSpace.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DebugUtils.h b/libs/ui/include_vndk/ui/DebugUtils.h
new file mode 120000
index 0000000..8461bb3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DebugUtils.h
@@ -0,0 +1 @@
+../../include/ui/DebugUtils.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h
new file mode 120000
index 0000000..75f14cf
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayInfo.h
@@ -0,0 +1 @@
+../../include/ui/DisplayInfo.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayStatInfo.h b/libs/ui/include_vndk/ui/DisplayStatInfo.h
new file mode 120000
index 0000000..6689ad3
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayStatInfo.h
@@ -0,0 +1 @@
+../../include/ui/DisplayStatInfo.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Fence.h b/libs/ui/include_vndk/ui/Fence.h
new file mode 120000
index 0000000..b110201
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Fence.h
@@ -0,0 +1 @@
+../../include/ui/Fence.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FenceTime.h b/libs/ui/include_vndk/ui/FenceTime.h
new file mode 120000
index 0000000..01a6ff2
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FenceTime.h
@@ -0,0 +1 @@
+../../include/ui/FenceTime.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FloatRect.h b/libs/ui/include_vndk/ui/FloatRect.h
new file mode 120000
index 0000000..a526211
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FloatRect.h
@@ -0,0 +1 @@
+../../include/ui/FloatRect.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/FrameStats.h b/libs/ui/include_vndk/ui/FrameStats.h
new file mode 120000
index 0000000..e68e5c8
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FrameStats.h
@@ -0,0 +1 @@
+../../include/ui/FrameStats.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Gralloc2.h b/libs/ui/include_vndk/ui/Gralloc2.h
new file mode 120000
index 0000000..66098c4
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Gralloc2.h
@@ -0,0 +1 @@
+../../include/ui/Gralloc2.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBuffer.h b/libs/ui/include_vndk/ui/GraphicBuffer.h
new file mode 120000
index 0000000..445eae5
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBuffer.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBuffer.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBufferAllocator.h b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h
new file mode 120000
index 0000000..9634533
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBufferAllocator.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBufferAllocator.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicBufferMapper.h b/libs/ui/include_vndk/ui/GraphicBufferMapper.h
new file mode 120000
index 0000000..c3b3a7c
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicBufferMapper.h
@@ -0,0 +1 @@
+../../include/ui/GraphicBufferMapper.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/GraphicTypes.h b/libs/ui/include_vndk/ui/GraphicTypes.h
new file mode 120000
index 0000000..b1859e0
--- /dev/null
+++ b/libs/ui/include_vndk/ui/GraphicTypes.h
@@ -0,0 +1 @@
+../../include/ui/GraphicTypes.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/HdrCapabilities.h b/libs/ui/include_vndk/ui/HdrCapabilities.h
new file mode 120000
index 0000000..a240828
--- /dev/null
+++ b/libs/ui/include_vndk/ui/HdrCapabilities.h
@@ -0,0 +1 @@
+../../include/ui/HdrCapabilities.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/PixelFormat.h b/libs/ui/include_vndk/ui/PixelFormat.h
new file mode 120000
index 0000000..0aba056
--- /dev/null
+++ b/libs/ui/include_vndk/ui/PixelFormat.h
@@ -0,0 +1 @@
+../../include/ui/PixelFormat.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Point.h b/libs/ui/include_vndk/ui/Point.h
new file mode 120000
index 0000000..0aeda3e
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Point.h
@@ -0,0 +1 @@
+../../include/ui/Point.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Rect.h b/libs/ui/include_vndk/ui/Rect.h
new file mode 120000
index 0000000..01ed689
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Rect.h
@@ -0,0 +1 @@
+../../include/ui/Rect.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Region.h b/libs/ui/include_vndk/ui/Region.h
new file mode 120000
index 0000000..3f829bf
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Region.h
@@ -0,0 +1 @@
+../../include/ui/Region.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/UiConfig.h b/libs/ui/include_vndk/ui/UiConfig.h
new file mode 120000
index 0000000..f580ce1
--- /dev/null
+++ b/libs/ui/include_vndk/ui/UiConfig.h
@@ -0,0 +1 @@
+../../include/ui/UiConfig.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 08067fc..aef6428 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -27,3 +27,10 @@
     srcs: ["colorspace_test.cpp"],
     cflags: ["-Wall", "-Werror"],
 }
+
+cc_test {
+    name: "GraphicBuffer_test",
+    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+    srcs: ["GraphicBuffer_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
new file mode 100644
index 0000000..eb679ac
--- /dev/null
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "GraphicBufferTest"
+
+#include <ui/DetachedBufferHandle.h>
+#include <ui/GraphicBuffer.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+namespace {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+
+} // namespace
+
+class GraphicBufferTest : public testing::Test {};
+
+TEST_F(GraphicBufferTest, DetachedBuffer) {
+    sp<GraphicBuffer> buffer(
+            new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage));
+
+    // Currently a newly allocated GraphicBuffer is in legacy mode, i.e. not associated with
+    // BufferHub. But this may change in the future.
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+
+    pdx::LocalChannelHandle channel{nullptr, 1234};
+    EXPECT_TRUE(channel.valid());
+
+    std::unique_ptr<DetachedBufferHandle> handle = DetachedBufferHandle::Create(std::move(channel));
+    EXPECT_FALSE(channel.valid());
+    EXPECT_TRUE(handle->isValid());
+    EXPECT_TRUE(handle->handle().valid());
+
+    buffer->setDetachedBufferHandle(std::move(handle));
+    EXPECT_TRUE(handle == nullptr);
+    EXPECT_TRUE(buffer->isDetachedBuffer());
+
+    handle = buffer->takeDetachedBufferHandle();
+    EXPECT_TRUE(handle != nullptr);
+    EXPECT_TRUE(handle->isValid());
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+}
+
+} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index b7a6099..660a200 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -25,7 +25,9 @@
 using android::dvr::BufferHubDefs::IsBufferAcquired;
 using android::dvr::BufferHubDefs::IsBufferReleased;
 using android::dvr::BufferProducer;
+using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
+using android::pdx::Status;
 
 const int kWidth = 640;
 const int kHeight = 480;
@@ -717,3 +719,64 @@
   // Producer should be able to gain no matter what.
   EXPECT_EQ(0, p->GainAsync(&meta, &fence));
 }
+
+TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(p.get() != nullptr);
+  ASSERT_TRUE(c.get() != nullptr);
+
+  DvrNativeBufferMetadata metadata;
+  LocalHandle invalid_fence;
+
+  // Detach in posted state should fail.
+  EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
+  EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+  auto s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in acquired state should fail.
+  EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
+  s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in released state should fail.
+  EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
+  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+  s1 = p->Detach();
+  EXPECT_FALSE(s1);
+
+  // Detach in gained state should succeed.
+  EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
+  s1 = p->Detach();
+  EXPECT_TRUE(s1);
+
+  LocalChannelHandle detached_buffer = s1.take();
+  EXPECT_TRUE(detached_buffer.valid());
+
+  // Both producer and consumer should have hangup.
+  EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+  auto s2 = p->GetEventMask(POLLHUP);
+  EXPECT_TRUE(s2);
+  EXPECT_EQ(s2.get(), POLLHUP);
+
+  EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+  s2 = p->GetEventMask(POLLHUP);
+  EXPECT_TRUE(s2);
+  EXPECT_EQ(s2.get(), POLLHUP);
+
+  auto s3 = p->CreateConsumer();
+  EXPECT_FALSE(s3);
+  // Note that here the expected error code is EOPNOTSUPP as the socket towards
+  // ProducerChannel has been teared down.
+  EXPECT_EQ(s3.error(), EOPNOTSUPP);
+
+  s3 = c->CreateConsumer();
+  EXPECT_FALSE(s3);
+  // Note that here the expected error code is EPIPE returned from
+  // ConsumerChannel::HandleMessage as the socket is still open but the producer
+  // is gone.
+  EXPECT_EQ(s3.error(), EPIPE);
+}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 6db09a9..13971eb 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -608,5 +608,23 @@
                        : LocalChannelHandle{nullptr, -status.error()});
 }
 
+Status<LocalChannelHandle> BufferProducer::Detach() {
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Can only detach a BufferProducer when it's in gained state.
+    ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
+          ") is not in gained state.",
+          id(), buffer_state);
+    return {};
+  }
+
+  Status<LocalChannelHandle> status =
+      InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+  ALOGE_IF(!status,
+           "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+           status.GetErrorMessage().c_str());
+  return status;
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index c791250..32448a1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -217,6 +217,14 @@
   // succeeded, or a negative errno code if local error check fails.
   int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
 
+  // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+  // be called when a producer buffer has exclusive access to the buffer (i.e.
+  // in the gain'ed state). On the successful return of the IPC call, a new
+  // LocalChannelHandle representing a detached buffer will be returned and all
+  // existing producer and consumer channels will be closed. Further IPCs
+  // towards those channels will return error.
+  Status<LocalChannelHandle> Detach();
+
  private:
   friend BASE;
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index c70fffc..fabefd5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -373,6 +373,10 @@
     kOpConsumerAcquire,
     kOpConsumerRelease,
     kOpConsumerSetIgnore,
+    kOpProducerBufferDetach,
+    kOpConsumerBufferDetach,
+    kOpCreateDetachedBuffer,
+    kOpDetachedBufferPromote,
     kOpCreateProducerQueue,
     kOpCreateConsumerQueue,
     kOpGetQueueInfo,
@@ -400,6 +404,28 @@
   PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
                     void(LocalFence release_fence));
   PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
+  PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
+                    LocalChannelHandle(Void));
+
+  // Detaches a ConsumerBuffer from an existing producer/consumer set. Can only
+  // be called when the consumer is the only consumer and it has exclusive
+  // access to the buffer (i.e. in the acquired'ed state). On the successful
+  // return of the IPC call, a new DetachedBufferChannel handle will be returned
+  // and all existing producer and consumer channels will be closed. Further
+  // IPCs towards those channels will return error.
+  PDX_REMOTE_METHOD(ConsumerBufferDetach, kOpConsumerBufferDetach,
+                    LocalChannelHandle(Void));
+
+  // Creates a standalone DetachedBuffer not associated with any
+  // producer/consumer set.
+  PDX_REMOTE_METHOD(CreateDetachedBuffer, kOpCreateDetachedBuffer,
+                    LocalChannelHandle(Void));
+
+  // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
+  // DetachedBuffer channel will be closed automatically on successful IPC
+  // return. Further IPCs towards this channel will return error.
+  PDX_REMOTE_METHOD(DetachedBufferPromote, kOpDetachedBufferPromote,
+                    LocalChannelHandle(Void));
 
   // Buffer Queue Methods.
   PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
deleted file mode 100644
index 140ffc5..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-#ifndef ANDROID_DVR_NATIVE_BUFFER_H_
-#define ANDROID_DVR_NATIVE_BUFFER_H_
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <log/log.h>
-#include <ui/ANativeObjectBase.h>
-#include <utils/RefBase.h>
-#include <nativebase/nativebase.h>
-
-#include <private/dvr/buffer_hub_client.h>
-
-namespace android {
-namespace dvr {
-
-// ANativeWindowBuffer is the abstraction Android HALs and frameworks use to
-// pass around hardware graphics buffers. The following classes implement this
-// abstraction with different DVR backing buffers, all of which provide
-// different semantics on top of ion/gralloc buffers.
-
-// An implementation of ANativeWindowBuffer backed by an IonBuffer.
-class NativeBuffer
-    : public android::ANativeObjectBase<ANativeWindowBuffer, NativeBuffer,
-                                        android::LightRefBase<NativeBuffer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  explicit NativeBuffer(const std::shared_ptr<IonBuffer>& buffer)
-      : BASE(), buffer_(buffer), fence_(kEmptyFence) {
-    ANativeWindowBuffer::width = buffer->width();
-    ANativeWindowBuffer::height = buffer->height();
-    ANativeWindowBuffer::stride = buffer->stride();
-    ANativeWindowBuffer::format = buffer->format();
-    ANativeWindowBuffer::usage = buffer->usage();
-    handle = buffer_->handle();
-  }
-
-  virtual ~NativeBuffer() {}
-
-  std::shared_ptr<IonBuffer> buffer() { return buffer_; }
-  int fence() const { return fence_.Get(); }
-
-  void SetFence(int fence) { fence_.Reset(fence); }
-
- private:
-  friend class android::LightRefBase<NativeBuffer>;
-
-  std::shared_ptr<IonBuffer> buffer_;
-  pdx::LocalHandle fence_;
-
-  NativeBuffer(const NativeBuffer&) = delete;
-  void operator=(NativeBuffer&) = delete;
-};
-
-class NativeBufferProducer : public android::ANativeObjectBase<
-                                 ANativeWindowBuffer, NativeBufferProducer,
-                                 android::LightRefBase<NativeBufferProducer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer,
-                       EGLDisplay display, uint32_t surface_buffer_index)
-      : BASE(),
-        buffer_(buffer),
-        surface_buffer_index_(surface_buffer_index),
-        display_(display) {
-    ANativeWindowBuffer::width = buffer_->width();
-    ANativeWindowBuffer::height = buffer_->height();
-    ANativeWindowBuffer::stride = buffer_->stride();
-    ANativeWindowBuffer::format = buffer_->format();
-    ANativeWindowBuffer::usage = buffer_->usage();
-    ANativeWindowBuffer::handle = buffer_->native_handle();
-    if (display_) {
-      image_khr_ =
-          eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                            static_cast<ANativeWindowBuffer*>(this), nullptr);
-    } else {
-      image_khr_ = EGL_NO_IMAGE_KHR;
-    }
-  }
-
-  explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
-      : NativeBufferProducer(buffer, nullptr, 0) {}
-
-  virtual ~NativeBufferProducer() {
-    if (image_khr_ != EGL_NO_IMAGE_KHR)
-      eglDestroyImageKHR(display_, image_khr_);
-  }
-
-  EGLImageKHR image_khr() const { return image_khr_; }
-  std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
-  int release_fence() const { return release_fence_.Get(); }
-  uint32_t surface_buffer_index() const { return surface_buffer_index_; }
-
-  // Return the release fence, passing ownership to the caller.
-  pdx::LocalHandle ClaimReleaseFence() { return std::move(release_fence_); }
-
-  // Post the buffer consumer, closing the acquire and release fences.
-  int Post(int acquire_fence, uint64_t sequence) {
-    release_fence_.Close();
-    return buffer_->Post(pdx::LocalHandle(acquire_fence), sequence);
-  }
-
-  // Gain the buffer producer, closing the previous release fence if valid.
-  int Gain() { return buffer_->Gain(&release_fence_); }
-
-  // Asynchronously gain the buffer, closing the previous release fence.
-  int GainAsync() {
-    release_fence_.Close();
-    return buffer_->GainAsync();
-  }
-
- private:
-  friend class android::LightRefBase<NativeBufferProducer>;
-
-  std::shared_ptr<BufferProducer> buffer_;
-  pdx::LocalHandle release_fence_;
-  EGLImageKHR image_khr_;
-  uint32_t surface_buffer_index_;
-  EGLDisplay display_;
-
-  NativeBufferProducer(const NativeBufferProducer&) = delete;
-  void operator=(NativeBufferProducer&) = delete;
-};
-
-// NativeBufferConsumer is an implementation of ANativeWindowBuffer backed by a
-// BufferConsumer.
-class NativeBufferConsumer : public android::ANativeObjectBase<
-                                 ANativeWindowBuffer, NativeBufferConsumer,
-                                 android::LightRefBase<NativeBufferConsumer>> {
- public:
-  static constexpr int kEmptyFence = -1;
-
-  explicit NativeBufferConsumer(const std::shared_ptr<BufferConsumer>& buffer)
-      : BASE(), buffer_(buffer), acquire_fence_(kEmptyFence), sequence_(0) {
-    ANativeWindowBuffer::width = buffer_->width();
-    ANativeWindowBuffer::height = buffer_->height();
-    ANativeWindowBuffer::stride = buffer_->stride();
-    ANativeWindowBuffer::format = buffer_->format();
-    ANativeWindowBuffer::usage = buffer_->usage();
-    handle = buffer_->native_handle();
-  }
-
-  virtual ~NativeBufferConsumer() {}
-
-  std::shared_ptr<BufferConsumer> buffer() const { return buffer_; }
-  int acquire_fence() const { return acquire_fence_.Get(); }
-  uint64_t sequence() const { return sequence_; }
-
-  // Return the acquire fence, passing ownership to the caller.
-  pdx::LocalHandle ClaimAcquireFence() { return std::move(acquire_fence_); }
-
-  // Acquire the underlying buffer consumer, closing the previous acquire fence
-  // if valid.
-  int Acquire() { return buffer_->Acquire(&acquire_fence_, &sequence_); }
-
-  // Release the buffer consumer, closing the acquire and release fences if
-  // valid.
-  int Release(int release_fence) {
-    acquire_fence_.Close();
-    sequence_ = 0;
-    return buffer_->Release(pdx::LocalHandle(release_fence));
-  }
-
- private:
-  friend class android::LightRefBase<NativeBufferConsumer>;
-
-  std::shared_ptr<BufferConsumer> buffer_;
-  pdx::LocalHandle acquire_fence_;
-  uint64_t sequence_;
-
-  NativeBufferConsumer(const NativeBufferConsumer&) = delete;
-  void operator=(NativeBufferConsumer&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_NATIVE_BUFFER_H_
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 442c82d..f67e258 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -9,7 +9,6 @@
 #include <mutex>
 
 #include <private/dvr/display_protocol.h>
-#include <private/dvr/native_buffer.h>
 
 using android::pdx::ErrorStatus;
 using android::pdx::LocalHandle;
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 0ee77f4..32d40e8 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -594,9 +594,10 @@
 
   if (socket_fd_ && event.data.fd == socket_fd_.Get()) {
     auto status = AcceptConnection(message);
-    if (!status)
-      return status;
-    return ReenableEpollEvent(socket_fd_.Borrow());
+    auto reenable_status = ReenableEpollEvent(socket_fd_.Borrow());
+    if (!reenable_status)
+      return reenable_status;
+    return status;
   }
 
   BorrowedHandle channel_fd{event.data.fd};
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 3e4a42c..4dc669b 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -72,6 +72,7 @@
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
 
+    clang: true,
     cflags: [
         "-DLOG_TAG=\"vr_flinger\"",
         "-DTRACE=0",
@@ -83,6 +84,9 @@
         "-Wno-error=sign-compare", // to fix later
         "-Wno-unused-variable",
     ],
+    cppflags: [
+        "-std=c++1z"
+    ],
     shared_libs: sharedLibraries,
     whole_static_libs: staticLibraries,
     header_libs: headerLibraries,
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index a18ff1a..87162c0 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -177,12 +177,12 @@
 
 Status<display::Metrics> DisplayService::OnGetMetrics(
     pdx::Message& /*message*/) {
-  return {{static_cast<uint32_t>(GetDisplayMetrics().width),
-           static_cast<uint32_t>(GetDisplayMetrics().height),
-           static_cast<uint32_t>(GetDisplayMetrics().dpi.x),
-           static_cast<uint32_t>(GetDisplayMetrics().dpi.y),
-           static_cast<uint32_t>(
-               hardware_composer_.native_display_metrics().vsync_period_ns),
+  const auto& params = hardware_composer_.GetPrimaryDisplayParams();
+  return {{static_cast<uint32_t>(params.width),
+           static_cast<uint32_t>(params.height),
+           static_cast<uint32_t>(params.dpi.x),
+           static_cast<uint32_t>(params.dpi.y),
+           static_cast<uint32_t>(params.vsync_period_ns),
            0,
            0,
            0,
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 316f15a..3090bd1 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -65,10 +65,6 @@
     hardware_composer_.SetVSyncCallback(callback);
   }
 
-  HWCDisplayMetrics GetDisplayMetrics() {
-    return hardware_composer_.display_metrics();
-  }
-
   void GrantDisplayOwnership() { hardware_composer_.Enable(); }
   void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
   void OnBootFinished() { hardware_composer_.OnBootFinished(); }
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index be8a721..44ce78c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -45,17 +45,22 @@
 
 namespace {
 
-const char kBacklightBrightnessSysFile[] =
-    "/sys/class/leds/lcd-backlight/brightness";
-
 const char kDvrPerformanceProperty[] = "sys.dvr.performance";
 const char kDvrStandaloneProperty[] = "ro.boot.vr";
 
 const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
 
+const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display";
+
 // How long to wait after boot finishes before we turn the display off.
 constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
 
+constexpr int kDefaultDisplayWidth = 1920;
+constexpr int kDefaultDisplayHeight = 1080;
+constexpr int64_t kDefaultVsyncPeriodNs = 16666667;
+// Hardware composer reports dpi as dots per thousand inches (dpi * 1000).
+constexpr int kDefaultDpi = 400000;
+
 // Get time offset from a vsync to when the pose for that vsync should be
 // predicted out to. For example, if scanout gets halfway through the frame
 // at the halfway point between vsyncs, then this could be half the period.
@@ -112,6 +117,11 @@
 #define TRACE_FORMAT(format, ...) \
   TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
 
+// Returns "primary" or "external". Useful for writing more readable logs.
+const char* GetDisplayName(bool is_primary) {
+  return is_primary ? "primary" : "external";
+}
+
 }  // anonymous namespace
 
 HardwareComposer::HardwareComposer()
@@ -135,42 +145,7 @@
 
   request_display_callback_ = request_display_callback;
 
-  HWC::Error error = HWC::Error::None;
-
-  Hwc2::Config config;
-  error = composer->getActiveConfig(primary_display_id, &config);
-
-  if (error != HWC::Error::None) {
-    ALOGE("HardwareComposer: Failed to get current display config : %d",
-          config);
-    return false;
-  }
-
-  error = GetDisplayMetrics(composer, primary_display_id, config,
-                            &native_display_metrics_);
-
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer: Failed to get display attributes for current "
-        "configuration : %d",
-        error.value);
-    return false;
-  }
-
-  ALOGI(
-      "HardwareComposer: primary display attributes: width=%d height=%d "
-      "vsync_period_ns=%d DPI=%dx%d",
-      native_display_metrics_.width, native_display_metrics_.height,
-      native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
-      native_display_metrics_.dpi.y);
-
-  // Set the display metrics but never use rotation to avoid the long latency of
-  // rotation processing in hwc.
-  display_transform_ = HWC_TRANSFORM_NONE;
-  display_metrics_ = native_display_metrics_;
-
-  // Setup the display metrics used by all Layer instances.
-  Layer::SetDisplayMetrics(native_display_metrics_);
+  primary_display_ = GetDisplayParams(composer, primary_display_id, true);
 
   post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   LOG_ALWAYS_FATAL_IF(
@@ -239,50 +214,38 @@
   }
 }
 
+void HardwareComposer::CreateComposer() {
+  if (composer_)
+    return;
+  composer_.reset(new Hwc2::impl::Composer("default"));
+  composer_callback_ = new ComposerCallback;
+  composer_->registerCallback(composer_callback_);
+  LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(),
+      "Registered composer callback but didn't get hotplug for primary"
+      " display");
+}
+
 void HardwareComposer::OnPostThreadResumed() {
-  // Phones create a new composer client on resume and destroy it on pause.
-  // Standalones only create the composer client once and then use SetPowerMode
-  // to control the screen on pause/resume.
-  if (!is_standalone_device_ || !composer_) {
-    composer_.reset(new Hwc2::impl::Composer("default"));
-    composer_callback_ = new ComposerCallback;
-    composer_->registerCallback(composer_callback_);
-    LOG_ALWAYS_FATAL_IF(!composer_callback_->HasDisplayId(),
-        "Registered composer callback but didn't get primary display");
-    Layer::SetComposer(composer_.get());
-    Layer::SetDisplayId(composer_callback_->GetDisplayId());
-  } else {
-    SetPowerMode(true);
-  }
-
-  EnableVsync(true);
-
-  // TODO(skiazyk): We need to do something about accessing this directly,
-  // supposedly there is a backlight service on the way.
-  // TODO(steventhomas): When we change the backlight setting, will surface
-  // flinger (or something else) set it back to its original value once we give
-  // control of the display back to surface flinger?
-  SetBacklightBrightness(255);
+  ALOGI("OnPostThreadResumed");
+  EnableDisplay(*target_display_, true);
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "performance");
 }
 
 void HardwareComposer::OnPostThreadPaused() {
+  ALOGI("OnPostThreadPaused");
   retire_fence_fds_.clear();
   layers_.clear();
 
-  if (composer_) {
-    EnableVsync(false);
-  }
-
+  // Phones create a new composer client on resume and destroy it on pause.
+  // Standalones only create the composer client once and then use SetPowerMode
+  // to control the screen on pause/resume.
   if (!is_standalone_device_) {
     composer_callback_ = nullptr;
     composer_.reset(nullptr);
-    Layer::SetComposer(nullptr);
-    Layer::SetDisplayId(0);
   } else {
-    SetPowerMode(false);
+    EnableDisplay(*target_display_, false);
   }
 
   // Trigger target-specific performance mode change.
@@ -315,28 +278,55 @@
       composer_->validateDisplay(display, &num_types, &num_requests);
 
   if (error == HWC2_ERROR_HAS_CHANGES) {
-    // TODO(skiazyk): We might need to inspect the requested changes first, but
-    // so far it seems like we shouldn't ever hit a bad state.
-    // error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
-    //                                               display);
+    ALOGE("Hardware composer has requested composition changes, "
+          "which we don't support.");
+    // Accept the changes anyway and see if we can get something on the screen.
     error = composer_->acceptDisplayChanges(display);
   }
 
   return error;
 }
 
-HWC::Error HardwareComposer::EnableVsync(bool enabled) {
-  return composer_->setVsyncEnabled(
-      composer_callback_->GetDisplayId(),
+bool HardwareComposer::EnableVsync(const DisplayParams& display, bool enabled) {
+  HWC::Error error = composer_->setVsyncEnabled(display.id,
       (Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
                                              : HWC2_VSYNC_DISABLE));
+  if (error != HWC::Error::None) {
+    ALOGE("Error attempting to %s vsync on %s display: %s",
+        enabled ? "enable" : "disable", GetDisplayName(display.is_primary),
+        error.to_string().c_str());
+  }
+  return error == HWC::Error::None;
 }
 
-HWC::Error HardwareComposer::SetPowerMode(bool active) {
+bool HardwareComposer::SetPowerMode(const DisplayParams& display, bool active) {
+  ALOGI("Turning %s display %s", GetDisplayName(display.is_primary),
+      active ? "on" : "off");
   HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
-  return composer_->setPowerMode(
-      composer_callback_->GetDisplayId(),
+  HWC::Error error = composer_->setPowerMode(display.id,
       power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+  if (error != HWC::Error::None) {
+    ALOGE("Error attempting to turn %s display %s: %s",
+          GetDisplayName(display.is_primary), active ? "on" : "off",
+        error.to_string().c_str());
+  }
+  return error == HWC::Error::None;
+}
+
+bool HardwareComposer::EnableDisplay(const DisplayParams& display,
+                                     bool enabled) {
+  bool power_result;
+  bool vsync_result;
+  // When turning a display on, we set the power state then set vsync. When
+  // turning a display off we do it in the opposite order.
+  if (enabled) {
+    power_result = SetPowerMode(display, enabled);
+    vsync_result = EnableVsync(display, enabled);
+  } else {
+    vsync_result = EnableVsync(display, enabled);
+    power_result = SetPowerMode(display, enabled);
+  }
+  return power_result && vsync_result;
 }
 
 HWC::Error HardwareComposer::Present(hwc2_display_t display) {
@@ -355,78 +345,105 @@
   return error;
 }
 
-HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer,
-                                                 hwc2_display_t display,
-                                                 hwc2_config_t config,
-                                                 hwc2_attribute_t attribute,
-                                                 int32_t* out_value) const {
-  return composer->getDisplayAttribute(
-      display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
-}
+DisplayParams HardwareComposer::GetDisplayParams(
+    Hwc2::Composer* composer, hwc2_display_t display, bool is_primary) {
+  DisplayParams params;
+  params.id = display;
+  params.is_primary = is_primary;
 
-HWC::Error HardwareComposer::GetDisplayMetrics(
-    Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config,
-    HWCDisplayMetrics* out_metrics) const {
-  HWC::Error error;
+  Hwc2::Config config;
+  HWC::Error error = composer->getActiveConfig(display, &config);
 
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH,
-                              &out_metrics->width);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display width: %s",
-        error.to_string().c_str());
-    return error;
+  if (error == HWC::Error::None) {
+    auto get_attr = [&](hwc2_attribute_t attr, const char* attr_name)
+        -> std::optional<int32_t> {
+      int32_t val;
+      HWC::Error error = composer->getDisplayAttribute(
+          display, config, (Hwc2::IComposerClient::Attribute)attr, &val);
+      if (error != HWC::Error::None) {
+        ALOGE("Failed to get %s display attr %s: %s",
+            GetDisplayName(is_primary), attr_name,
+            error.to_string().c_str());
+        return std::nullopt;
+      }
+      return val;
+    };
+
+    auto width = get_attr(HWC2_ATTRIBUTE_WIDTH, "width");
+    auto height = get_attr(HWC2_ATTRIBUTE_HEIGHT, "height");
+
+    if (width && height) {
+      params.width = *width;
+      params.height = *height;
+    } else {
+      ALOGI("Failed to get width and/or height for %s display. Using default"
+          " size %dx%d.", GetDisplayName(is_primary), kDefaultDisplayWidth,
+          kDefaultDisplayHeight);
+      params.width = kDefaultDisplayWidth;
+      params.height = kDefaultDisplayHeight;
+    }
+
+    auto vsync_period = get_attr(HWC2_ATTRIBUTE_VSYNC_PERIOD, "vsync period");
+    if (vsync_period) {
+      params.vsync_period_ns = *vsync_period;
+    } else {
+      ALOGI("Failed to get vsync period for %s display. Using default vsync"
+          " period %.2fms", GetDisplayName(is_primary),
+          static_cast<float>(kDefaultVsyncPeriodNs) / 1000000);
+      params.vsync_period_ns = kDefaultVsyncPeriodNs;
+    }
+
+    auto dpi_x = get_attr(HWC2_ATTRIBUTE_DPI_X, "DPI X");
+    auto dpi_y = get_attr(HWC2_ATTRIBUTE_DPI_Y, "DPI Y");
+    if (dpi_x && dpi_y) {
+      params.dpi.x = *dpi_x;
+      params.dpi.y = *dpi_y;
+    } else {
+      ALOGI("Failed to get dpi_x and/or dpi_y for %s display. Using default"
+          " dpi %d.", GetDisplayName(is_primary), kDefaultDpi);
+      params.dpi.x = kDefaultDpi;
+      params.dpi.y = kDefaultDpi;
+    }
+  } else {
+    ALOGE("HardwareComposer: Failed to get current %s display config: %d."
+        " Using default display values.",
+        GetDisplayName(is_primary), error.value);
+    params.width = kDefaultDisplayWidth;
+    params.height = kDefaultDisplayHeight;
+    params.dpi.x = kDefaultDpi;
+    params.dpi.y = kDefaultDpi;
+    params.vsync_period_ns = kDefaultVsyncPeriodNs;
   }
 
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT,
-                              &out_metrics->height);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s",
-        error.to_string().c_str());
-    return error;
-  }
+  ALOGI(
+      "HardwareComposer: %s display attributes: width=%d height=%d "
+      "vsync_period_ns=%d DPI=%dx%d",
+      GetDisplayName(is_primary),
+      params.width,
+      params.height,
+      params.vsync_period_ns,
+      params.dpi.x,
+      params.dpi.y);
 
-  error = GetDisplayAttribute(composer, display, config,
-                              HWC2_ATTRIBUTE_VSYNC_PERIOD,
-                              &out_metrics->vsync_period_ns);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display height: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X,
-                              &out_metrics->dpi.x);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display DPI X: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y,
-                              &out_metrics->dpi.y);
-  if (error != HWC::Error::None) {
-    ALOGE(
-        "HardwareComposer::GetDisplayMetrics: Failed to get display DPI Y: %s",
-        error.to_string().c_str());
-    return error;
-  }
-
-  return HWC::Error::None;
+  return params;
 }
 
 std::string HardwareComposer::Dump() {
   std::unique_lock<std::mutex> lock(post_thread_mutex_);
   std::ostringstream stream;
 
-  stream << "Display metrics:     " << display_metrics_.width << "x"
-         << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
-         << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
-         << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
-         << std::endl;
+  auto print_display_metrics = [&](const DisplayParams& params) {
+    stream << GetDisplayName(params.is_primary)
+           << " display metrics:     " << params.width << "x"
+           << params.height << " " << (params.dpi.x / 1000.0)
+           << "x" << (params.dpi.y / 1000.0) << " dpi @ "
+           << (1000000000.0 / params.vsync_period_ns) << " Hz"
+           << std::endl;
+  };
+
+  print_display_metrics(primary_display_);
+  if (external_display_)
+    print_display_metrics(*external_display_);
 
   stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
   stream << "Active layers:       " << layers_.size() << std::endl;
@@ -449,7 +466,7 @@
   return stream.str();
 }
 
-void HardwareComposer::PostLayers() {
+void HardwareComposer::PostLayers(hwc2_display_t display) {
   ATRACE_NAME("HardwareComposer::PostLayers");
 
   // Setup the hardware composer layers with current buffers.
@@ -497,14 +514,14 @@
   }
 #endif
 
-  HWC::Error error = Validate(composer_callback_->GetDisplayId());
+  HWC::Error error = Validate(display);
   if (error != HWC::Error::None) {
-    ALOGE("HardwareComposer::PostLayers: Validate failed: %s",
-          error.to_string().c_str());
+    ALOGE("HardwareComposer::PostLayers: Validate failed: %s display=%" PRIu64,
+          error.to_string().c_str(), display);
     return;
   }
 
-  error = Present(composer_callback_->GetDisplayId());
+  error = Present(display);
   if (error != HWC::Error::None) {
     ALOGE("HardwareComposer::PostLayers: Present failed: %s",
           error.to_string().c_str());
@@ -513,7 +530,7 @@
 
   std::vector<Hwc2::Layer> out_layers;
   std::vector<int> out_fences;
-  error = composer_->getReleaseFences(composer_callback_->GetDisplayId(),
+  error = composer_->getReleaseFences(display,
                                       &out_layers, &out_fences);
   ALOGE_IF(error != HWC::Error::None,
            "HardwareComposer::PostLayers: Failed to get release fences: %s",
@@ -537,7 +554,8 @@
   const bool display_idle = surfaces.size() == 0;
   {
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    pending_surfaces_ = std::move(surfaces);
+    surfaces_ = std::move(surfaces);
+    surfaces_changed_ = true;
   }
 
   if (request_display_callback_ && !is_standalone_device_)
@@ -653,13 +671,11 @@
   }
 }
 
-// Waits for the next vsync and returns the timestamp of the vsync event. If
-// vsync already passed since the last call, returns the latest vsync timestamp
-// instead of blocking.
-Status<int64_t> HardwareComposer::WaitForVSync() {
-  const int64_t predicted_vsync_time =
-      last_vsync_timestamp_ +
-      display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+// Sleep until the next predicted vsync, returning the predicted vsync
+// timestamp.
+Status<int64_t> HardwareComposer::WaitForPredictedVSync() {
+  const int64_t predicted_vsync_time = last_vsync_timestamp_ +
+      (target_display_->vsync_period_ns * vsync_prediction_interval_);
   const int error = SleepUntil(predicted_vsync_time);
   if (error < 0) {
     ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
@@ -698,16 +714,6 @@
   bool thread_policy_setup =
       SetThreadPolicy("graphics:high", "/system/performance");
 
-#if ENABLE_BACKLIGHT_BRIGHTNESS
-  // TODO(hendrikw): This isn't required at the moment. It's possible that there
-  //                 is another method to access this when needed.
-  // Open the backlight brightness control sysfs node.
-  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
-  ALOGW_IF(!backlight_brightness_fd_,
-           "HardwareComposer: Failed to open backlight brightness control: %s",
-           strerror(errno));
-#endif  // ENABLE_BACKLIGHT_BRIGHTNESS
-
   // Create a timerfd based on CLOCK_MONOTINIC.
   vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
   LOG_ALWAYS_FATAL_IF(
@@ -715,20 +721,28 @@
       "HardwareComposer: Failed to create vsync sleep timerfd: %s",
       strerror(errno));
 
-  const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
-  const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
-
-  // TODO(jbates) Query vblank time from device, when such an API is available.
-  // This value (6.3%) was measured on A00 in low persistence mode.
-  int64_t vblank_ns = ns_per_frame * 63 / 1000;
-  int64_t right_eye_photon_offset_ns = (ns_per_frame - vblank_ns) / 2;
-
-  // Check property for overriding right eye offset value.
-  right_eye_photon_offset_ns =
-      property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
-
+  struct VsyncEyeOffsets { int64_t left_ns, right_ns; };
   bool was_running = false;
 
+  auto get_vsync_eye_offsets = [this]() -> VsyncEyeOffsets {
+    VsyncEyeOffsets offsets;
+    offsets.left_ns =
+        GetPosePredictionTimeOffset(target_display_->vsync_period_ns);
+
+    // TODO(jbates) Query vblank time from device, when such an API is
+    // available. This value (6.3%) was measured on A00 in low persistence mode.
+    int64_t vblank_ns = target_display_->vsync_period_ns * 63 / 1000;
+    offsets.right_ns = (target_display_->vsync_period_ns - vblank_ns) / 2;
+
+    // Check property for overriding right eye offset value.
+    offsets.right_ns =
+        property_get_int64(kRightEyeOffsetProperty, offsets.right_ns);
+
+    return offsets;
+  };
+
+  VsyncEyeOffsets vsync_eye_offsets = get_vsync_eye_offsets();
+
   if (is_standalone_device_) {
     // First, wait until boot finishes.
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
@@ -747,8 +761,8 @@
                         "Vr flinger should own the display by now.");
     post_thread_resumed_ = true;
     post_thread_ready_.notify_all();
-    OnPostThreadResumed();
-    was_running = true;
+    if (!composer_)
+      CreateComposer();
   }
 
   while (1) {
@@ -761,10 +775,8 @@
       std::unique_lock<std::mutex> lock(post_thread_mutex_);
       ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
 
-      // Tear down resources if necessary.
-      if (was_running)
-        OnPostThreadPaused();
-
+      // Tear down resources.
+      OnPostThreadPaused();
       was_running = false;
       post_thread_resumed_ = false;
       post_thread_ready_.notify_all();
@@ -781,10 +793,18 @@
       ALOGI("HardwareComposer::PostThread: Exiting quiescent state.");
     }
 
-    if (!was_running) {
-      // Setup resources.
+    if (!composer_)
+      CreateComposer();
+
+    bool target_display_changed = UpdateTargetDisplay();
+    bool just_resumed_running = !was_running;
+    was_running = true;
+
+    if (target_display_changed)
+      vsync_eye_offsets = get_vsync_eye_offsets();
+
+    if (just_resumed_running) {
       OnPostThreadResumed();
-      was_running = true;
 
       // Try to setup the scheduler policy if it failed during startup. Only
       // attempt to do this on transitions from inactive to active to avoid
@@ -793,12 +813,16 @@
         thread_policy_setup =
             SetThreadPolicy("graphics:high", "/system/performance");
       }
+    }
 
+    if (target_display_changed || just_resumed_running) {
       // Initialize the last vsync timestamp with the current time. The
       // predictor below uses this time + the vsync interval in absolute time
       // units for the initial delay. Once the driver starts reporting vsync the
       // predictor will sync up with the real vsync.
       last_vsync_timestamp_ = GetSystemClockNs();
+      vsync_prediction_interval_ = 1;
+      retire_fence_fds_.clear();
     }
 
     int64_t vsync_timestamp = 0;
@@ -808,7 +832,7 @@
                    vsync_count_ + 1, last_vsync_timestamp_,
                    vsync_prediction_interval_);
 
-      auto status = WaitForVSync();
+      auto status = WaitForPredictedVSync();
       ALOGE_IF(
           !status,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
@@ -829,16 +853,16 @@
     if (vsync_prediction_interval_ == 1)
       ++vsync_count_;
 
-    const bool layer_config_changed = UpdateLayerConfig();
+    UpdateLayerConfig();
 
     // Publish the vsync event.
     if (vsync_ring_) {
       DvrVsync vsync;
       vsync.vsync_count = vsync_count_;
       vsync.vsync_timestamp_ns = vsync_timestamp;
-      vsync.vsync_left_eye_offset_ns = photon_offset_ns;
-      vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns;
-      vsync.vsync_period_ns = ns_per_frame;
+      vsync.vsync_left_eye_offset_ns = vsync_eye_offsets.left_ns;
+      vsync.vsync_right_eye_offset_ns = vsync_eye_offsets.right_ns;
+      vsync.vsync_period_ns = target_display_->vsync_period_ns;
 
       vsync_ring_->Publish(vsync);
     }
@@ -852,7 +876,8 @@
       // Sleep until shortly before vsync.
       ATRACE_NAME("sleep");
 
-      const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame;
+      const int64_t display_time_est_ns =
+          vsync_timestamp + target_display_->vsync_period_ns;
       const int64_t now_ns = GetSystemClockNs();
       const int64_t sleep_time_ns = display_time_est_ns - now_ns -
                                     post_thread_config_.frame_post_offset_ns;
@@ -873,11 +898,7 @@
     }
 
     {
-      auto status = composer_callback_->GetVsyncTime();
-      if (!status) {
-        ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
-              status.GetErrorMessage().c_str());
-      }
+      auto status = composer_callback_->GetVsyncTime(target_display_->id);
 
       // If we failed to read vsync there might be a problem with the driver.
       // Since there's nothing we can do just behave as though we didn't get an
@@ -904,20 +925,84 @@
       }
     }
 
-    PostLayers();
+    PostLayers(target_display_->id);
   }
 }
 
+bool HardwareComposer::UpdateTargetDisplay() {
+  bool target_display_changed = false;
+  auto displays = composer_callback_->GetDisplays();
+  if (displays.external_display_was_hotplugged) {
+    bool was_using_external_display = !target_display_->is_primary;
+    if (was_using_external_display) {
+      // The external display was hotplugged, so make sure to ignore any bad
+      // display errors as we destroy the layers.
+      for (auto& layer: layers_)
+        layer.IgnoreBadDisplayErrorsOnDestroy(true);
+    }
+
+    if (displays.external_display) {
+      // External display was connected
+      external_display_ = GetDisplayParams(composer_.get(),
+          *displays.external_display, /*is_primary*/ false);
+
+      if (property_get_bool(kUseExternalDisplayProperty, false)) {
+        ALOGI("External display connected. Switching to external display.");
+        target_display_ = &(*external_display_);
+        target_display_changed = true;
+      } else {
+        ALOGI("External display connected, but sysprop %s is unset, so"
+              " using primary display.", kUseExternalDisplayProperty);
+        if (was_using_external_display) {
+          target_display_ = &primary_display_;
+          target_display_changed = true;
+        }
+      }
+    } else {
+      // External display was disconnected
+      external_display_ = std::nullopt;
+      if (was_using_external_display) {
+        ALOGI("External display disconnected. Switching to primary display.");
+        target_display_ = &primary_display_;
+        target_display_changed = true;
+      }
+    }
+  }
+
+  if (target_display_changed) {
+    // If we're switching to the external display, turn the primary display off.
+    if (!target_display_->is_primary) {
+      EnableDisplay(primary_display_, false);
+    }
+    // If we're switching to the primary display, and the external display is
+    // still connected, turn the external display off.
+    else if (target_display_->is_primary && external_display_) {
+      EnableDisplay(*external_display_, false);
+    }
+
+    // Turn the new target display on.
+    EnableDisplay(*target_display_, true);
+
+    // When we switch displays we need to recreate all the layers, so clear the
+    // current list, which will trigger layer recreation.
+    layers_.clear();
+  }
+
+  return target_display_changed;
+}
+
 // Checks for changes in the surface stack and updates the layer config to
 // accomodate the new stack.
-bool HardwareComposer::UpdateLayerConfig() {
+void HardwareComposer::UpdateLayerConfig() {
   std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces;
   {
     std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    if (pending_surfaces_.empty())
-      return false;
 
-    surfaces = std::move(pending_surfaces_);
+    if (!surfaces_changed_ && (!layers_.empty() || surfaces_.empty()))
+      return;
+
+    surfaces = surfaces_;
+    surfaces_changed_ = false;
   }
 
   ATRACE_NAME("UpdateLayerConfig_HwLayers");
@@ -954,8 +1039,8 @@
       layers_.erase(search);
     } else {
       // Insert a layer for the new surface.
-      layers.emplace_back(surface, blending, display_transform_,
-                          HWC::Composition::Device, layer_index);
+      layers.emplace_back(composer_.get(), *target_display_, surface, blending,
+          HWC::Composition::Device, layer_index);
     }
 
     ALOGI_IF(
@@ -976,32 +1061,35 @@
 
   ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
            layers_.size());
-  return true;
 }
 
 void HardwareComposer::SetVSyncCallback(VSyncCallback callback) {
   vsync_callback_ = callback;
 }
 
-void HardwareComposer::SetBacklightBrightness(int brightness) {
-  if (backlight_brightness_fd_) {
-    std::array<char, 32> text;
-    const int length = snprintf(text.data(), text.size(), "%d", brightness);
-    write(backlight_brightness_fd_.Get(), text.data(), length);
-  }
-}
-
 Return<void> HardwareComposer::ComposerCallback::onHotplug(
     Hwc2::Display display, IComposerCallback::Connection conn) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  ALOGI("onHotplug display=%" PRIu64 " conn=%d", display, conn);
+
+  bool is_primary = !got_first_hotplug_ || display == primary_display_.id;
+
   // Our first onHotplug callback is always for the primary display.
-  //
-  // Ignore any other hotplug callbacks since the primary display is never
-  // disconnected and we don't care about other displays.
-  if (!has_display_id_) {
+  if (!got_first_hotplug_) {
     LOG_ALWAYS_FATAL_IF(conn != IComposerCallback::Connection::CONNECTED,
         "Initial onHotplug callback should be primary display connected");
-    has_display_id_ = true;
-    display_id_ = display;
+    got_first_hotplug_ = true;
+  } else if (is_primary) {
+    ALOGE("Ignoring unexpected onHotplug() call for primary display");
+    return Void();
+  }
+
+  if (conn == IComposerCallback::Connection::CONNECTED) {
+    if (!is_primary)
+      external_display_ = DisplayInfo();
+    DisplayInfo& display_info = is_primary ?
+        primary_display_ : *external_display_;
+    display_info.id = display;
 
     std::array<char, 1024> buffer;
     snprintf(buffer.data(), buffer.size(),
@@ -1011,15 +1099,20 @@
           "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
           "vsync_event node for display %" PRIu64,
           display);
-      driver_vsync_event_fd_ = std::move(handle);
+      display_info.driver_vsync_event_fd = std::move(handle);
     } else {
       ALOGI(
           "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
           "support vsync_event node for display %" PRIu64,
           display);
     }
+  } else if (conn == IComposerCallback::Connection::DISCONNECTED) {
+    external_display_ = std::nullopt;
   }
 
+  if (!is_primary)
+    external_display_was_hotplugged_ = true;
+
   return Void();
 }
 
@@ -1030,23 +1123,45 @@
 
 Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
                                                          int64_t timestamp) {
-  // Ignore any onVsync callbacks for the non-primary display.
-  if (has_display_id_ && display == display_id_) {
+  DisplayInfo* display_info = GetDisplayInfo(display);
+  if (display_info) {
     TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
                  display, timestamp);
-    callback_vsync_timestamp_ = timestamp;
+    display_info->callback_vsync_timestamp = timestamp;
   }
+
   return Void();
 }
 
-Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime() {
+HardwareComposer::ComposerCallback::Displays
+HardwareComposer::ComposerCallback::GetDisplays() {
+  std::lock_guard<std::mutex> lock(mutex_);
+  Displays displays;
+  displays.primary_display = primary_display_.id;
+  if (external_display_)
+    displays.external_display = external_display_->id;
+  if (external_display_was_hotplugged_) {
+    external_display_was_hotplugged_ = false;
+    displays.external_display_was_hotplugged = true;
+  }
+  return displays;
+}
+
+Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
+    hwc2_display_t display) {
+  DisplayInfo* display_info = GetDisplayInfo(display);
+  if (!display_info) {
+    ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display);
+    return ErrorStatus(EINVAL);
+  }
+
   // See if the driver supports direct vsync events.
-  LocalHandle& event_fd = driver_vsync_event_fd_;
+  LocalHandle& event_fd = display_info->driver_vsync_event_fd;
   if (!event_fd) {
     // Fall back to returning the last timestamp returned by the vsync
     // callback.
-    std::lock_guard<std::mutex> autolock(vsync_mutex_);
-    return callback_vsync_timestamp_;
+    std::lock_guard<std::mutex> autolock(mutex_);
+    return display_info->callback_vsync_timestamp;
   }
 
   // When the driver supports the vsync_event sysfs node we can use it to
@@ -1094,19 +1209,32 @@
   return {timestamp};
 }
 
-Hwc2::Composer* Layer::composer_{nullptr};
-HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0};
-hwc2_display_t Layer::display_id_{0};
+HardwareComposer::ComposerCallback::DisplayInfo*
+HardwareComposer::ComposerCallback::GetDisplayInfo(hwc2_display_t display) {
+  if (display == primary_display_.id) {
+    return &primary_display_;
+  } else if (external_display_ && display == external_display_->id) {
+    return &(*external_display_);
+  }
+  return nullptr;
+}
 
 void Layer::Reset() {
   if (hardware_composer_layer_) {
-    composer_->destroyLayer(display_id_, hardware_composer_layer_);
+    HWC::Error error =
+        composer_->destroyLayer(display_params_.id, hardware_composer_layer_);
+    if (error != HWC::Error::None &&
+        (!ignore_bad_display_errors_on_destroy_ ||
+         error != HWC::Error::BadDisplay)) {
+      ALOGE("destroyLayer() failed for display %" PRIu64 ", layer %" PRIu64
+          ". error: %s", display_params_.id, hardware_composer_layer_,
+          error.to_string().c_str());
+    }
     hardware_composer_layer_ = 0;
   }
 
   z_order_ = 0;
   blending_ = HWC::BlendMode::None;
-  transform_ = HWC::Transform::None;
   composition_type_ = HWC::Composition::Invalid;
   target_composition_type_ = composition_type_;
   source_ = EmptyVariant{};
@@ -1114,25 +1242,29 @@
   surface_rect_functions_applied_ = false;
   pending_visibility_settings_ = true;
   cached_buffer_map_.clear();
+  ignore_bad_display_errors_on_destroy_ = false;
 }
 
-Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
-             HWC::BlendMode blending, HWC::Transform transform,
-             HWC::Composition composition_type, size_t z_order)
-    : z_order_{z_order},
+Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+             const std::shared_ptr<DirectDisplaySurface>& surface,
+             HWC::BlendMode blending, HWC::Composition composition_type,
+             size_t z_order)
+    : composer_(composer),
+      display_params_(display_params),
+      z_order_{z_order},
       blending_{blending},
-      transform_{transform},
       target_composition_type_{composition_type},
       source_{SourceSurface{surface}} {
   CommonLayerSetup();
 }
 
-Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-             HWC::Transform transform, HWC::Composition composition_type,
-             size_t z_order)
-    : z_order_{z_order},
+Layer::Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+             const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+             HWC::Composition composition_type, size_t z_order)
+    : composer_(composer),
+      display_params_(display_params),
+      z_order_{z_order},
       blending_{blending},
-      transform_{transform},
       target_composition_type_{composition_type},
       source_{SourceBuffer{buffer}} {
   CommonLayerSetup();
@@ -1146,10 +1278,11 @@
   if (this != &other) {
     Reset();
     using std::swap;
+    swap(composer_, other.composer_);
+    swap(display_params_, other.display_params_);
     swap(hardware_composer_layer_, other.hardware_composer_layer_);
     swap(z_order_, other.z_order_);
     swap(blending_, other.blending_);
-    swap(transform_, other.transform_);
     swap(composition_type_, other.composition_type_);
     swap(target_composition_type_, other.target_composition_type_);
     swap(source_, other.source_);
@@ -1158,6 +1291,8 @@
          other.surface_rect_functions_applied_);
     swap(pending_visibility_settings_, other.pending_visibility_settings_);
     swap(cached_buffer_map_, other.cached_buffer_map_);
+    swap(ignore_bad_display_errors_on_destroy_,
+         other.ignore_bad_display_errors_on_destroy_);
   }
   return *this;
 }
@@ -1197,14 +1332,14 @@
     HWC::Error error;
 
     error = composer_->setLayerBlendMode(
-        display_id_, hardware_composer_layer_,
+        display_params_.id, hardware_composer_layer_,
         blending_.cast<Hwc2::IComposerClient::BlendMode>());
     ALOGE_IF(error != HWC::Error::None,
              "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
              error.to_string().c_str());
 
-    error = composer_->setLayerZOrder(display_id_, hardware_composer_layer_,
-                                      z_order_);
+    error = composer_->setLayerZOrder(display_params_.id,
+        hardware_composer_layer_, z_order_);
     ALOGE_IF(error != HWC::Error::None,
              "Layer::UpdateLayerSettings: Error setting z_ order: %s",
              error.to_string().c_str());
@@ -1219,28 +1354,28 @@
   // TODO(eieio): Use surface attributes or some other mechanism to control
   // the layer display frame.
   error = composer_->setLayerDisplayFrame(
-      display_id_, hardware_composer_layer_,
-      {0, 0, display_metrics_.width, display_metrics_.height});
+      display_params_.id, hardware_composer_layer_,
+      {0, 0, display_params_.width, display_params_.height});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer display frame: %s",
            error.to_string().c_str());
 
   error = composer_->setLayerVisibleRegion(
-      display_id_, hardware_composer_layer_,
-      {{0, 0, display_metrics_.width, display_metrics_.height}});
+      display_params_.id, hardware_composer_layer_,
+      {{0, 0, display_params_.width, display_params_.height}});
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer visible region: %s",
            error.to_string().c_str());
 
-  error = composer_->setLayerPlaneAlpha(display_id_, hardware_composer_layer_,
-                                        1.0f);
+  error = composer_->setLayerPlaneAlpha(display_params_.id,
+      hardware_composer_layer_, 1.0f);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
            error.to_string().c_str());
 }
 
 void Layer::CommonLayerSetup() {
-  HWC::Error error = composer_->createLayer(display_id_,
+  HWC::Error error = composer_->createLayer(display_params_.id,
                                             &hardware_composer_layer_);
   ALOGE_IF(error != HWC::Error::None,
            "Layer::CommonLayerSetup: Failed to create layer on primary "
@@ -1285,10 +1420,10 @@
     if (composition_type_ == HWC::Composition::Invalid) {
       composition_type_ = HWC::Composition::SolidColor;
       composer_->setLayerCompositionType(
-          display_id_, hardware_composer_layer_,
+          display_params_.id, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
       Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
-      composer_->setLayerColor(display_id_, hardware_composer_layer_,
+      composer_->setLayerColor(display_params_.id, hardware_composer_layer_,
                                layer_color);
     } else {
       // The composition type is already set. Nothing else to do until a
@@ -1298,7 +1433,7 @@
     if (composition_type_ != target_composition_type_) {
       composition_type_ = target_composition_type_;
       composer_->setLayerCompositionType(
-          display_id_, hardware_composer_layer_,
+          display_params_.id, hardware_composer_layer_,
           composition_type_.cast<Hwc2::IComposerClient::Composition>());
     }
 
@@ -1309,7 +1444,7 @@
 
     HWC::Error error{HWC::Error::None};
     error =
-        composer_->setLayerBuffer(display_id_, hardware_composer_layer_,
+        composer_->setLayerBuffer(display_params_.id, hardware_composer_layer_,
                                   slot, handle, acquire_fence_.Get());
 
     ALOGE_IF(error != HWC::Error::None,
@@ -1319,7 +1454,7 @@
     if (!surface_rect_functions_applied_) {
       const float float_right = right;
       const float float_bottom = bottom;
-      error = composer_->setLayerSourceCrop(display_id_,
+      error = composer_->setLayerSourceCrop(display_params_.id,
                                             hardware_composer_layer_,
                                             {0, 0, float_right, float_bottom});
 
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 1d0c7ef..1d8d463 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -13,6 +13,7 @@
 #include <condition_variable>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <thread>
 #include <tuple>
 #include <vector>
@@ -35,16 +36,19 @@
 namespace android {
 namespace dvr {
 
-// Basic display metrics for physical displays. Dimensions and densities are
-// relative to the physical display orientation, which may be different from the
-// logical display orientation exposed to applications.
-struct HWCDisplayMetrics {
+// Basic display metrics for physical displays.
+struct DisplayParams {
+  hwc2_display_t id;
+  bool is_primary;
+
   int width;
   int height;
+
   struct {
     int x;
     int y;
   } dpi;
+
   int vsync_period_ns;
 };
 
@@ -58,26 +62,29 @@
   // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
   // every frame.
   //
+  // |composer| The composer instance.
+  // |display_params| Info about the display to use.
   // |blending| receives HWC_BLENDING_* values.
-  // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
   // |index| is the index of this surface in the DirectDisplaySurface array.
-  Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
-        HWC::BlendMode blending, HWC::Transform transform,
-        HWC::Composition composition_type, size_t z_roder);
+  Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+        const std::shared_ptr<DirectDisplaySurface>& surface,
+        HWC::BlendMode blending, HWC::Composition composition_type,
+        size_t z_order);
 
   // Sets up the layer to use a direct buffer as its content source. No special
   // handling of the buffer is performed; responsibility for updating or
   // changing the buffer each frame is on the caller.
   //
+  // |composer| The composer instance.
+  // |display_params| Info about the display to use.
   // |blending| receives HWC_BLENDING_* values.
-  // |transform| receives HWC_TRANSFORM_* values.
   // |composition_type| receives either HWC_FRAMEBUFFER for most layers or
   // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
-  Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
-        HWC::Transform transform, HWC::Composition composition_type,
-        size_t z_order);
+  Layer(Hwc2::Composer* composer, const DisplayParams& display_params,
+        const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+        HWC::Composition composition_type, size_t z_order);
 
   Layer(Layer&&);
   Layer& operator=(Layer&&);
@@ -144,17 +151,8 @@
   }
   bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
 
-  // Sets the composer instance used by all Layer instances.
-  static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
-
-  // Sets the display metrics used by all Layer instances.
-  static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) {
-    display_metrics_ = display_metrics;
-  }
-
-  // Sets the display id used by all Layer instances.
-  static void SetDisplayId(hwc2_display_t display_id) {
-    display_id_ = display_id;
+  void IgnoreBadDisplayErrorsOnDestroy(bool ignore) {
+    ignore_bad_display_errors_on_destroy_ = ignore;
   }
 
  private:
@@ -174,21 +172,11 @@
   // associated and always returns false.
   bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
 
-  // Composer instance shared by all instances of Layer. This must be set
-  // whenever a new instance of the Composer is created. This may be set to
-  // nullptr as long as there are no instances of Layer that might need to use
-  // it.
-  static Hwc2::Composer* composer_;
+  // Composer instance.
+  Hwc2::Composer* composer_ = nullptr;
 
-  // Display metrics shared by all instances of Layer. This must be set at least
-  // once during VrFlinger initialization and is expected to remain constant
-  // thereafter.
-  static HWCDisplayMetrics display_metrics_;
-
-  // Id of the primary display. Shared by all instances of Layer. This must be
-  // set whenever the primary display id changes. This can be left unset as long
-  // as there are no instances of Layer that might need to use it.
-  static hwc2_display_t display_id_;
+  // Parameters of the display to use for this layer.
+  DisplayParams display_params_;
 
   // The hardware composer layer and metrics to use during the prepare cycle.
   hwc2_layer_t hardware_composer_layer_ = 0;
@@ -197,7 +185,6 @@
   // Prepare phase.
   size_t z_order_ = 0;
   HWC::BlendMode blending_ = HWC::BlendMode::None;
-  HWC::Transform transform_ = HWC::Transform::None;
   HWC::Composition composition_type_ = HWC::Composition::Invalid;
   HWC::Composition target_composition_type_ = HWC::Composition::Device;
 
@@ -293,6 +280,12 @@
   // importing a buffer HWC already knows about.
   std::map<std::size_t, int> cached_buffer_map_;
 
+  // When calling destroyLayer() on an external display that's been removed we
+  // typically get HWC2_ERROR_BAD_DISPLAY errors. If
+  // ignore_bad_display_errors_on_destroy_ is true, don't log the bad display
+  // errors, since they're expected.
+  bool ignore_bad_display_errors_on_destroy_ = false;
+
   Layer(const Layer&) = delete;
   void operator=(const Layer&) = delete;
 };
@@ -330,22 +323,12 @@
   // Called on a binder thread.
   void OnBootFinished();
 
-  // Get the HMD display metrics for the current display.
-  display::Metrics GetHmdDisplayMetrics() const;
-
   std::string Dump();
 
   void SetVSyncCallback(VSyncCallback callback);
 
-  // Metrics of the logical display, which is always landscape.
-  int DisplayWidth() const { return display_metrics_.width; }
-  int DisplayHeight() const { return display_metrics_.height; }
-  HWCDisplayMetrics display_metrics() const { return display_metrics_; }
-
-  // Metrics of the native display, which depends on the specific hardware
-  // implementation of the display.
-  HWCDisplayMetrics native_display_metrics() const {
-    return native_display_metrics_;
+  const DisplayParams& GetPrimaryDisplayParams() const {
+    return primary_display_;
   }
 
   // Sets the display surfaces to compose the hardware layer stack.
@@ -356,16 +339,16 @@
   void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
 
  private:
-  HWC::Error GetDisplayAttribute(Hwc2::Composer* composer,
-                                 hwc2_display_t display, hwc2_config_t config,
-                                 hwc2_attribute_t attributes,
-                                 int32_t* out_value) const;
-  HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display,
-                               hwc2_config_t config,
-                               HWCDisplayMetrics* out_metrics) const;
+  DisplayParams GetDisplayParams(Hwc2::Composer* composer,
+      hwc2_display_t display, bool is_primary);
 
-  HWC::Error EnableVsync(bool enabled);
-  HWC::Error SetPowerMode(bool active);
+  // Turn display vsync on/off. Returns true on success, false on failure.
+  bool EnableVsync(const DisplayParams& display, bool enabled);
+  // Turn display power on/off. Returns true on success, false on failure.
+  bool SetPowerMode(const DisplayParams& display, bool active);
+  // Convenience function to turn a display on/off. Turns both power and vsync
+  // on/off. Returns true on success, false on failure.
+  bool EnableDisplay(const DisplayParams& display, bool enabled);
 
   class ComposerCallback : public Hwc2::IComposerCallback {
    public:
@@ -376,24 +359,38 @@
     hardware::Return<void> onVsync(Hwc2::Display display,
                                    int64_t timestamp) override;
 
-    bool HasDisplayId() { return has_display_id_; }
-    hwc2_display_t GetDisplayId() { return display_id_; }
-    pdx::Status<int64_t> GetVsyncTime();
+    bool GotFirstHotplug() { return got_first_hotplug_; }
+
+    struct Displays {
+      hwc2_display_t primary_display = 0;
+      std::optional<hwc2_display_t> external_display;
+      bool external_display_was_hotplugged = false;
+    };
+
+    Displays GetDisplays();
+    pdx::Status<int64_t> GetVsyncTime(hwc2_display_t display);
 
    private:
-    std::mutex vsync_mutex_;
-    bool has_display_id_ = false;
-    hwc2_display_t display_id_;
-    pdx::LocalHandle driver_vsync_event_fd_;
-    int64_t callback_vsync_timestamp_{0};
+    struct DisplayInfo {
+      hwc2_display_t id = 0;
+      pdx::LocalHandle driver_vsync_event_fd;
+      int64_t callback_vsync_timestamp{0};
+    };
+
+    DisplayInfo* GetDisplayInfo(hwc2_display_t display);
+
+    std::mutex mutex_;
+
+    bool got_first_hotplug_ = false;
+    DisplayInfo primary_display_;
+    std::optional<DisplayInfo> external_display_;
+    bool external_display_was_hotplugged_ = false;
   };
 
   HWC::Error Validate(hwc2_display_t display);
   HWC::Error Present(hwc2_display_t display);
 
-  void SetBacklightBrightness(int brightness);
-
-  void PostLayers();
+  void PostLayers(hwc2_display_t display);
   void PostThread();
 
   // The post thread has two controlling states:
@@ -421,16 +418,24 @@
   int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
                                   int requested_events, int timeout_ms);
 
-  // WaitForVSync and SleepUntil are blocking calls made on the post thread that
-  // can be interrupted by a control thread. If interrupted, these calls return
-  // kPostThreadInterrupted.
+  // WaitForPredictedVSync and SleepUntil are blocking calls made on the post
+  // thread that can be interrupted by a control thread. If interrupted, these
+  // calls return kPostThreadInterrupted.
   int ReadWaitPPState();
-  pdx::Status<int64_t> WaitForVSync();
+  pdx::Status<int64_t> WaitForPredictedVSync();
   int SleepUntil(int64_t wakeup_timestamp);
 
+  // Initialize any newly connected displays, and set target_display_ to the
+  // display we should render to. Returns true if target_display_
+  // changed. Called only from the post thread.
+  bool UpdateTargetDisplay();
+
   // Reconfigures the layer stack if the display surfaces changed since the last
   // frame. Called only from the post thread.
-  bool UpdateLayerConfig();
+  void UpdateLayerConfig();
+
+  // Called on the post thread to create the Composer instance.
+  void CreateComposer();
 
   // Called on the post thread when the post thread is resumed.
   void OnPostThreadResumed();
@@ -461,18 +466,19 @@
   sp<ComposerCallback> composer_callback_;
   RequestDisplayCallback request_display_callback_;
 
-  // Display metrics of the physical display.
-  HWCDisplayMetrics native_display_metrics_;
-  // Display metrics of the logical display, adjusted so that orientation is
-  // landscape.
-  HWCDisplayMetrics display_metrics_;
-  // Transform required to get from native to logical display orientation.
-  HWC::Transform display_transform_ = HWC::Transform::None;
+  DisplayParams primary_display_;
+  std::optional<DisplayParams> external_display_;
+  DisplayParams* target_display_ = &primary_display_;
 
-  // Pending surface list. Set by the display service when DirectSurfaces are
-  // added, removed, or change visibility. Written by the message dispatch
-  // thread and read by the post thread.
-  std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_;
+  // The list of surfaces we should draw. Set by the display service when
+  // DirectSurfaces are added, removed, or change visibility. Written by the
+  // message dispatch thread and read by the post thread.
+  std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces_;
+  // Set to true by the dispatch thread whenever surfaces_ changes. Set to false
+  // by the post thread when the new list of surfaces is processed.
+  bool surfaces_changed_ = false;
+
+  std::vector<std::shared_ptr<DirectDisplaySurface>> current_surfaces_;
 
   // Layer set for handling buffer flow into hardware composer layers. This
   // vector must be sorted by surface_id in ascending order.
@@ -499,9 +505,6 @@
   // notified via post_thread_wait_.
   bool boot_finished_ = false;
 
-  // Backlight LED brightness sysfs node.
-  pdx::LocalHandle backlight_brightness_fd_;
-
   // VSync sleep timerfd.
   pdx::LocalHandle vsync_sleep_timer_fd_;
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index b453d19..f3a9ad8 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -94,6 +94,7 @@
 char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
         "EGL_KHR_image_base "                   // mandatory
+        "EGL_KHR_image_gl_colorspace "
         "EGL_KHR_image_pixmap "
         "EGL_KHR_lock_surface "
         "EGL_KHR_gl_colorspace "
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c3f4f58..9a449fa 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -105,6 +105,36 @@
     return value ? "true" : "false";
 }
 
+static std::string motionActionToString(int32_t action) {
+    // Convert MotionEvent action to string
+    switch(action & AMOTION_EVENT_ACTION_MASK) {
+        case AMOTION_EVENT_ACTION_DOWN:
+            return "DOWN";
+        case AMOTION_EVENT_ACTION_MOVE:
+            return "MOVE";
+        case AMOTION_EVENT_ACTION_UP:
+            return "UP";
+        case AMOTION_EVENT_ACTION_POINTER_DOWN:
+            return "POINTER_DOWN";
+        case AMOTION_EVENT_ACTION_POINTER_UP:
+            return "POINTER_UP";
+    }
+    return StringPrintf("%" PRId32, action);
+}
+
+static std::string keyActionToString(int32_t action) {
+    // Convert KeyEvent action to string
+    switch(action) {
+        case AKEY_EVENT_ACTION_DOWN:
+            return "DOWN";
+        case AKEY_EVENT_ACTION_UP:
+            return "UP";
+        case AKEY_EVENT_ACTION_MULTIPLE:
+            return "MULTIPLE";
+    }
+    return StringPrintf("%" PRId32, action);
+}
+
 static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
     return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
             >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
@@ -3976,11 +4006,11 @@
 }
 
 void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%d, "
+    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%s, "
             "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
             "repeatCount=%d), policyFlags=0x%08x",
-            deviceId, source, action, flags, keyCode, scanCode, metaState,
-            repeatCount, policyFlags);
+            deviceId, source, keyActionToString(action).c_str(), flags, keyCode,
+            scanCode, metaState, repeatCount, policyFlags);
 }
 
 void InputDispatcher::KeyEntry::recycle() {
@@ -4021,11 +4051,11 @@
 }
 
 void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%s, actionButton=0x%08x, "
             "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
             "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
-            deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
-            xPrecision, yPrecision, displayId);
+            deviceId, source, motionActionToString(action).c_str(), actionButton, flags, metaState,
+            buttonState, edgeFlags, xPrecision, yPrecision, displayId);
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
             msg += ", ";
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 2bd0a19..8e9e7fd 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -86,6 +86,7 @@
 SensorService::SensorService()
     : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
       mWakeLockAcquired(false) {
+    mUidPolicy = new UidPolicy(this);
 }
 
 bool SensorService::initializeHmacKey() {
@@ -283,7 +284,6 @@
             enableSchedFifoMode();
 
             // Start watching UID changes to apply policy.
-            mUidPolicy = new UidPolicy(this);
             mUidPolicy->registerSelf();
         }
     }
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0c0fedc..ff994f5 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -87,6 +87,7 @@
         "BufferLayerConsumer.cpp",
         "Client.cpp",
         "ColorLayer.cpp",
+        "ContainerLayer.cpp",
         "DisplayDevice.cpp",
         "DisplayHardware/ComposerHal.cpp",
         "DisplayHardware/FramebufferSurface.cpp",
@@ -104,6 +105,7 @@
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
+        "LayerStats.cpp",
         "LayerVector.cpp",
         "MessageQueue.cpp",
         "MonitoredProducer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b804af8..82300e6 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -631,7 +631,7 @@
 
     const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
     error = hwcLayer->setHdrMetadata(metadata);
-    if (error != HWC2::Error::None) {
+    if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
         ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
@@ -690,9 +690,9 @@
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         Mutex::Autolock lock(mQueueItemLock);
-        mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
-                                                item.mGraphicBuffer->getHeight(),
-                                                item.mFrameNumber);
+        mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+                                                 item.mGraphicBuffer->getHeight(),
+                                                 item.mFrameNumber);
         // Reset the frame number tracker when we receive the first buffer after
         // a frame number reset
         if (item.mFrameNumber == 1) {
@@ -829,7 +829,7 @@
                               getColor());
     engine.setSourceDataSpace(mCurrentState.dataSpace);
 
-    if (mCurrentState.dataSpace == HAL_DATASPACE_BT2020_ITU_PQ &&
+    if (mCurrentState.dataSpace == ui::Dataspace::BT2020_ITU_PQ &&
         mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
         getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102) {
         engine.setSourceY410BT2020(true);
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 46ec0e3..6b4f5db 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -65,7 +65,7 @@
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentFence(Fence::NO_FENCE),
         mCurrentTimestamp(0),
-        mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
+        mCurrentDataSpace(ui::Dataspace::UNKNOWN),
         mCurrentFrameNumber(0),
         mCurrentTransformToDisplayInverse(false),
         mCurrentSurfaceDamage(),
@@ -341,7 +341,7 @@
     mCurrentTransform = item.mTransform;
     mCurrentScalingMode = item.mScalingMode;
     mCurrentTimestamp = item.mTimestamp;
-    mCurrentDataSpace = item.mDataSpace;
+    mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace);
     mCurrentHdrMetadata = item.mHdrMetadata;
     mCurrentFence = item.mFence;
     mCurrentFenceTime = item.mFenceTime;
@@ -445,7 +445,7 @@
     return mCurrentTimestamp;
 }
 
-android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
+ui::Dataspace BufferLayerConsumer::getCurrentDataSpace() {
     BLC_LOGV("getCurrentDataSpace");
     Mutex::Autolock lock(mMutex);
     return mCurrentDataSpace;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 11048d8..f81cdb1 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -23,6 +23,7 @@
 
 #include <ui/FenceTime.h>
 #include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 
 #include <utils/String8.h>
@@ -122,7 +123,7 @@
 
     // getDataSpace retrieves the DataSpace associated with the texture image
     // set by the most recent call to updateTexImage.
-    android_dataspace getCurrentDataSpace();
+    ui::Dataspace getCurrentDataSpace();
 
     // getCurrentHdrMetadata retrieves the HDR metadata associated with the
     // texture image set by the most recent call to updateTexImage.
@@ -324,7 +325,7 @@
 
     // mCurrentDataSpace is the dataspace for the current texture. It
     // gets set each time updateTexImage is called.
-    android_dataspace mCurrentDataSpace;
+    ui::Dataspace mCurrentDataSpace;
 
     // mCurrentHdrMetadata is the HDR metadata for the current texture. It
     // gets set each time updateTexImage is called.
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0c9f0e2..c90024b 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -143,7 +143,7 @@
 status_t Client::createSurface(
         const String8& name,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-        const sp<IBinder>& parentHandle, uint32_t windowType, uint32_t ownerUid,
+        const sp<IBinder>& parentHandle, int32_t windowType, int32_t ownerUid,
         sp<IBinder>* handle,
         sp<IGraphicBufferProducer>* gbp)
 {
@@ -180,13 +180,13 @@
         PixelFormat format;
         uint32_t flags;
         sp<Layer>* parent;
-        uint32_t windowType;
-        uint32_t ownerUid;
+        int32_t windowType;
+        int32_t ownerUid;
     public:
         MessageCreateLayer(SurfaceFlinger* flinger,
                 const String8& name, Client* client,
                 uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-                sp<IBinder>* handle, uint32_t windowType, uint32_t ownerUid,
+                sp<IBinder>* handle, int32_t windowType, int32_t ownerUid,
                 sp<IGraphicBufferProducer>* gbp,
                 sp<Layer>* parent)
             : flinger(flinger), client(client),
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 2aab28f..c7df9f7 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -58,7 +58,7 @@
     virtual status_t createSurface(
             const String8& name,
             uint32_t w, uint32_t h,PixelFormat format, uint32_t flags,
-            const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
+            const sp<IBinder>& parent, int32_t windowType, int32_t ownerUid,
             sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp);
 
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 4022b31..0cde398 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -13,16 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#ifndef ANDROID_COLOR_LAYER_H
-#define ANDROID_COLOR_LAYER_H
-
-#include <stdint.h>
 #include <sys/types.h>
 
-#include "Layer.h"
+#include <cstdint>
 
-// ---------------------------------------------------------------------------
+#include "Layer.h"
 
 namespace android {
 
@@ -36,36 +33,8 @@
     virtual void onDraw(const RenderArea& renderArea, const Region& clip,
                         bool useIdentityTransform) const;
     bool isVisible() const override;
-    virtual bool isOpaque(const Layer::State&) const { return false; }
-    virtual bool isFixedSize() const { return true; }
 
-    void notifyAvailableFrames() override {}
-    PixelFormat getPixelFormat() const override { return PIXEL_FORMAT_NONE; }
-    uint32_t getEffectiveScalingMode() const override { return 0; }
-    void releasePendingBuffer(nsecs_t) override {}
-    Region latchBuffer(bool&, nsecs_t) override { return Region(); }
-    void useSurfaceDamage() override {}
-    void useEmptyDamage() override {}
-    bool isBufferLatched() const override { return false; }
-    bool onPreComposition(nsecs_t) override { return true; }
-    void abandon() override {}
     void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
-    void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) override {}
-    bool shouldPresentNow(const DispSync& /*dispSync*/) const override { return false; }
-    bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
-                           const std::shared_ptr<FenceTime>& /*presentFence*/,
-                           const CompositorTiming& /*compositorTiming*/) override {
-        return false;
-    }
-    void setTransformHint(uint32_t /*orientation*/) const override {}
-    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) override {
-        return {};
-    }
-    bool getTransformToDisplayInverse() const override { return false; }
 };
 
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_COLOR_LAYER_H
+} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
new file mode 100644
index 0000000..f259d93
--- /dev/null
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "ContainerLayer"
+
+#include "ContainerLayer.h"
+
+namespace android {
+
+ContainerLayer::ContainerLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+                               const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+      : Layer(flinger, client, name, w, h, flags) {
+    mDrawingState = mCurrentState;
+}
+
+void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
+
+bool ContainerLayer::isVisible() const {
+    return !isHiddenByPolicy();
+}
+
+void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+
+} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
new file mode 100644
index 0000000..543f60a
--- /dev/null
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <cstdint>
+
+#include "Layer.h"
+
+namespace android {
+
+class ContainerLayer : public Layer {
+public:
+    ContainerLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+                   uint32_t w, uint32_t h, uint32_t flags);
+    virtual ~ContainerLayer() = default;
+
+    const char* getTypeId() const override { return "ContainerLayer"; }
+    void onDraw(const RenderArea& renderArea, const Region& clip,
+                bool useIdentityTransform) const override;
+    bool isVisible() const override;
+
+    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d40666e..58a774b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -49,16 +49,12 @@
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 
-// ----------------------------------------------------------------------------
-using namespace android;
-// ----------------------------------------------------------------------------
+namespace android {
 
 // retrieve triple buffer setting from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
-
-static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3;
+using android::ui::ColorMode;
 
 /*
  * Initialize the display to the specified values.
@@ -74,72 +70,44 @@
         int32_t hwcId,
         bool isSecure,
         const wp<IBinder>& displayToken,
+        const sp<ANativeWindow>& nativeWindow,
         const sp<DisplaySurface>& displaySurface,
-        const sp<IGraphicBufferProducer>& producer,
+        std::unique_ptr<RE::Surface> renderSurface,
+        int displayWidth,
+        int displayHeight,
         bool supportWideColor,
-        bool supportHdr)
+        bool supportHdr,
+        int initialPowerMode)
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
       mType(type),
       mHwcDisplayId(hwcId),
       mDisplayToken(displayToken),
+      mNativeWindow(nativeWindow),
       mDisplaySurface(displaySurface),
-      mSurface{flinger->getRenderEngine().createSurface()},
-      mDisplayWidth(),
-      mDisplayHeight(),
-      mPageFlipCount(),
+      mSurface{std::move(renderSurface)},
+      mDisplayWidth(displayWidth),
+      mDisplayHeight(displayHeight),
+      mPageFlipCount(0),
       mIsSecure(isSecure),
       mLayerStack(NO_LAYER_STACK),
       mOrientation(),
-      mPowerMode(HWC_POWER_MODE_OFF),
-      mActiveConfig(0)
+      mViewport(Rect::INVALID_RECT),
+      mFrame(Rect::INVALID_RECT),
+      mPowerMode(initialPowerMode),
+      mActiveConfig(0),
+      mActiveColorMode(ColorMode::NATIVE),
+      mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
+      mDisplayHasWideColor(supportWideColor),
+      mDisplayHasHdr(supportHdr)
 {
     // clang-format on
-    Surface* surface;
-    mNativeWindow = surface = new Surface(producer, false);
-    ANativeWindow* const window = mNativeWindow.get();
-
-    mActiveColorMode = HAL_COLOR_MODE_NATIVE;
-    mDisplayHasWideColor = supportWideColor;
-    mDisplayHasHdr = supportHdr;
-
-    /*
-     * Create our display's surface
-     */
-    mSurface->setCritical(mType == DisplayDevice::DISPLAY_PRIMARY);
-    mSurface->setAsync(mType >= DisplayDevice::DISPLAY_VIRTUAL);
-    mSurface->setNativeWindow(window);
-    mDisplayWidth = mSurface->queryWidth();
-    mDisplayHeight = mSurface->queryHeight();
-
-    // Make sure that composition can never be stalled by a virtual display
-    // consumer that isn't processing buffers fast enough. We have to do this
-    // in two places:
-    // * Here, in case the display is composed entirely by HWC.
-    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
-    //   window's swap interval in eglMakeCurrent, so they'll override the
-    //   interval we set here.
-    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
-        window->setSwapInterval(window, 0);
-
-    mPageFlipCount = 0;
-    mViewport.makeInvalid();
-    mFrame.makeInvalid();
-
-    // virtual displays are always considered enabled
-    mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?
-                  HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
 
     // initialize the display orientation transform.
     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
-
-    if (useTripleFramebuffer) {
-        surface->allocateBuffers();
-    }
 }
 
-DisplayDevice::~DisplayDevice() {
-}
+DisplayDevice::~DisplayDevice() = default;
 
 void DisplayDevice::disconnect(HWComposer& hwc) {
     if (mHwcDisplayId >= 0) {
@@ -292,17 +260,27 @@
 }
 
 // ----------------------------------------------------------------------------
-void DisplayDevice::setActiveColorMode(android_color_mode_t mode) {
+void DisplayDevice::setActiveColorMode(ColorMode mode) {
     mActiveColorMode = mode;
 }
 
-android_color_mode_t DisplayDevice::getActiveColorMode() const {
+ColorMode DisplayDevice::getActiveColorMode() const {
     return mActiveColorMode;
 }
 
-void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
+void DisplayDevice::setColorTransform(const mat4& transform) {
+    const bool isIdentity = (transform == mat4());
+    mColorTransform =
+            isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+android_color_transform_t DisplayDevice::getColorTransform() const {
+    return mColorTransform;
+}
+
+void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
     ANativeWindow* const window = mNativeWindow.get();
-    native_window_set_buffers_data_space(window, dataspace);
+    native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
 }
 
 // ----------------------------------------------------------------------------
@@ -485,8 +463,11 @@
                         mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
                         tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
     auto const surface = static_cast<Surface*>(window);
-    android_dataspace dataspace = surface->getBuffersDataSpace();
-    result.appendFormat("   dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace);
+    ui::Dataspace dataspace = surface->getBuffersDataSpace();
+    result.appendFormat("   wideColor=%d, hdr=%d, colorMode=%s, dataspace: %s (%d)\n",
+                        mDisplayHasWideColor, mDisplayHasHdr,
+                        decodeColorMode(mActiveColorMode).c_str(),
+                        dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
 
     String8 surfaceDump;
     mDisplaySurface->dumpAsString(surfaceDump);
@@ -506,3 +487,5 @@
     viewport.makeInvalid();
     frame.makeInvalid();
 }
+
+}  // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d5ed15f..e844d11 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -21,6 +21,8 @@
 
 #include <stdlib.h>
 
+#include <math/mat4.h>
+
 #include <ui/Region.h>
 
 #include <binder/IBinder.h>
@@ -31,6 +33,7 @@
 
 #include <gui/ISurfaceComposer.h>
 #include <hardware/hwcomposer_defs.h>
+#include <ui/GraphicTypes.h>
 #include "RenderArea.h"
 #include "RenderEngine/Surface.h"
 
@@ -76,9 +79,14 @@
             int32_t hwcId,
             bool isSecure,
             const wp<IBinder>& displayToken,
+            const sp<ANativeWindow>& nativeWindow,
             const sp<DisplaySurface>& displaySurface,
-            const sp<IGraphicBufferProducer>& producer,
-            bool supportWideColor, bool supportHdr);
+            std::unique_ptr<RE::Surface> renderSurface,
+            int displayWidth,
+            int displayHeight,
+            bool supportWideColor,
+            bool supportHdr,
+            int initialPowerMode);
     // clang-format on
 
     ~DisplayDevice();
@@ -155,9 +163,11 @@
     void setPowerMode(int mode);
     bool isDisplayOn() const;
 
-    android_color_mode_t getActiveColorMode() const;
-    void setActiveColorMode(android_color_mode_t mode);
-    void setCompositionDataSpace(android_dataspace dataspace);
+    ui::ColorMode getActiveColorMode() const;
+    void setActiveColorMode(ui::ColorMode mode);
+    android_color_transform_t getColorTransform() const;
+    void setColorTransform(const mat4& transform);
+    void setCompositionDataSpace(ui::Dataspace dataspace);
 
     /* ------------------------------------------------------------------------
      * Display active config management.
@@ -230,7 +240,9 @@
     // Current active config
     int mActiveConfig;
     // current active color mode
-    android_color_mode_t mActiveColorMode;
+    ui::ColorMode mActiveColorMode;
+    // Current color transform
+    android_color_transform_t mColorTransform;
 
     // Need to know if display is wide-color capable or not.
     // Initialized by SurfaceFlinger when the DisplayDevice is created.
@@ -279,7 +291,7 @@
     bool needsFiltering() const override { return mDevice->needsFiltering(); }
     Rect getSourceCrop() const override { return mSourceCrop; }
     bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); }
-    android_color_mode_t getActiveColorMode() const override {
+    ui::ColorMode getActiveColorMode() const override {
         return mDevice->getActiveColorMode();
     }
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index bb720f7..bbffd0a 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -32,6 +32,7 @@
 using hardware::Return;
 using hardware::hidl_vec;
 using hardware::hidl_handle;
+using namespace hardware::graphics::common;
 using namespace hardware::graphics::composer;
 using PerFrameMetadata = hardware::graphics::composer::V2_2::IComposerClient::PerFrameMetadata;
 using PerFrameMetadataKey =
@@ -256,17 +257,32 @@
 {
     const uint32_t bufferSlotCount = 1;
     Error error = kDefaultError;
-    mClient->createVirtualDisplay(width, height, *format, bufferSlotCount,
-            [&](const auto& tmpError, const auto& tmpDisplay,
-                const auto& tmpFormat) {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
+    if (mClient_2_2) {
+        mClient_2_2->createVirtualDisplay_2_2(width, height, *format, bufferSlotCount,
+                [&](const auto& tmpError, const auto& tmpDisplay,
+                    const auto& tmpFormat) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
 
-                *outDisplay = tmpDisplay;
-                *format = tmpFormat;
+                    *outDisplay = tmpDisplay;
+                    *format = tmpFormat;
+                });
+    } else {
+        mClient->createVirtualDisplay(width, height,
+                static_cast<V1_0::PixelFormat>(*format), bufferSlotCount,
+                [&](const auto& tmpError, const auto& tmpDisplay,
+                    const auto& tmpFormat) {
+                    error = tmpError;
+                    if (error != Error::NONE) {
+                        return;
+                    }
+
+                    *outDisplay = tmpDisplay;
+                    *format = static_cast<PixelFormat>(tmpFormat);
             });
+    }
 
     return error;
 }
@@ -522,7 +538,7 @@
             .height = target->getHeight(),
             .stride = target->getStride(),
             .layerCount = target->getLayerCount(),
-            .format = static_cast<PixelFormat>(target->getPixelFormat()),
+            .format = static_cast<V1_0::PixelFormat>(target->getPixelFormat()),
             .usage = target->getUsage(),
         };
         mWriter.setClientTargetMetadata(metadata);
@@ -645,7 +661,7 @@
             .height = buffer->getHeight(),
             .stride = buffer->getStride(),
             .layerCount = buffer->getLayerCount(),
-            .format = static_cast<PixelFormat>(buffer->getPixelFormat()),
+            .format = static_cast<V1_0::PixelFormat>(buffer->getPixelFormat()),
             .usage = buffer->getUsage(),
         };
         mWriter.setLayerBufferMetadata(metadata);
@@ -706,6 +722,9 @@
 }
 
 Error Composer::setLayerHdrMetadata(Display display, Layer layer, const HdrMetadata& metadata) {
+    if (!mClient_2_2) {
+        return Error::UNSUPPORTED;
+    }
 
     mWriter.selectDisplay(display);
     mWriter.selectLayer(layer);
@@ -739,7 +758,7 @@
                                   metadata.cta8613.maxFrameAverageLightLevel}});
     }
 
-    mWriter.setPerFrameMetadata(composerMetadata);
+    mWriter.setLayerPerFrameMetadata(composerMetadata);
     return Error::NONE;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c0373aa..98f2f9d 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/composer/2.2/IComposer.h>
 #include <android/hardware/graphics/composer/2.2/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
@@ -39,10 +40,10 @@
 
 using android::hardware::graphics::common::V1_0::ColorMode;
 using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::PixelFormat;
 
 using android::hardware::graphics::composer::V2_1::Config;
 using android::hardware::graphics::composer::V2_1::Display;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 4faba3b..e6d7834 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -44,6 +44,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+using ui::Dataspace;
+
 /*
  * This implements the (main) framebuffer management. This class is used
  * mostly by SurfaceFlinger, but also by command line GL application.
@@ -92,7 +94,7 @@
     uint32_t slot = 0;
     sp<GraphicBuffer> buf;
     sp<Fence> acquireFence(Fence::NO_FENCE);
-    android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+    Dataspace dataspace = Dataspace::UNKNOWN;
     status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
     mDataSpace = dataspace;
     if (result != NO_ERROR) {
@@ -104,7 +106,7 @@
 
 status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
         sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
-        android_dataspace_t& outDataspace) {
+        Dataspace& outDataspace) {
     Mutex::Autolock lock(mMutex);
 
     BufferItem item;
@@ -139,7 +141,7 @@
     outFence = item.mFence;
     mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
             &outSlot, &outBuffer);
-    outDataspace = item.mDataSpace;
+    outDataspace = static_cast<Dataspace>(item.mDataSpace);
     status_t result =
             mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
@@ -177,9 +179,10 @@
 
 void FramebufferSurface::dumpAsString(String8& result) const {
     Mutex::Autolock lock(mMutex);
-    result.appendFormat("FramebufferSurface: dataspace: %s(%d)\n",
-                        dataspaceDetails(mDataSpace).c_str(), mDataSpace);
-    ConsumerBase::dumpLocked(result, "");
+    result.appendFormat("  FramebufferSurface: dataspace: %s(%d)\n",
+                        dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+                        mDataSpace);
+    ConsumerBase::dumpLocked(result, "   ");
 }
 
 void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index ed756c4..0fd8e9e 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -61,7 +61,7 @@
     // BufferQueue and releases the previously latched buffer to the
     // BufferQueue.  The new buffer is returned in the 'buffer' argument.
     status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
-            sp<Fence>& outFence, android_dataspace_t& outDataspace);
+            sp<Fence>& outFence, ui::Dataspace& outDataspace);
 
     // mDisplayType must match one of the HWC display types
     int mDisplayType;
@@ -76,7 +76,7 @@
     // compositing. Otherwise it will display the dataspace of the buffer
     // use for compositing which can change as wide-color content is
     // on/off.
-    android_dataspace mDataSpace;
+    ui::Dataspace mDataSpace;
 
     // mCurrentBuffer is the current buffer or nullptr to indicate that there is
     // no current buffer.
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index f14c2fe..2686788 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -47,6 +47,9 @@
 namespace HWC2 {
 
 namespace Hwc2 = android::Hwc2;
+using android::ui::ColorMode;
+using android::ui::Dataspace;
+using android::ui::PixelFormat;
 
 namespace {
 
@@ -114,14 +117,13 @@
 }
 
 Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
-        android_pixel_format_t* format, Display** outDisplay)
+        PixelFormat* format, Display** outDisplay)
 {
     ALOGI("Creating virtual display");
 
     hwc2_display_t displayId = 0;
-    auto intFormat = static_cast<Hwc2::PixelFormat>(*format);
     auto intError = mComposer->createVirtualDisplay(width, height,
-            &intFormat, &displayId);
+            format, &displayId);
     auto error = static_cast<Error>(intError);
     if (error != Error::None) {
         return error;
@@ -129,8 +131,8 @@
 
     auto display = std::make_unique<Display>(
             *mComposer.get(), mCapabilities, displayId, DisplayType::Virtual);
+    display->setConnected(true);
     *outDisplay = display.get();
-    *format = static_cast<android_pixel_format_t>(intFormat);
     mDisplays.emplace(displayId, std::move(display));
     ALOGI("Created virtual display");
     return Error::None;
@@ -144,31 +146,32 @@
 
 void Device::onHotplug(hwc2_display_t displayId, Connection connection) {
     if (connection == Connection::Connected) {
-        auto display = getDisplayById(displayId);
-        if (display) {
-            if (display->isConnected()) {
-                ALOGW("Attempt to hotplug connect display %" PRIu64
-                        " , which is already connected.", displayId);
-            } else {
-                display->setConnected(true);
-            }
-        } else {
-            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<Display>(
-                    *mComposer.get(), mCapabilities, displayId, displayType);
-            mDisplays.emplace(displayId, std::move(newDisplay));
+        // If we get a hotplug connected event for a display we already have,
+        // destroy the display and recreate it. This will force us to requery
+        // the display params and recreate all layers on that display.
+        auto oldDisplay = getDisplayById(displayId);
+        if (oldDisplay != nullptr && oldDisplay->isConnected()) {
+            ALOGI("Hotplug connecting an already connected display."
+                    " Clearing old display state.");
         }
+        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<Display>(
+                *mComposer.get(), mCapabilities, displayId, displayType);
+        newDisplay->setConnected(true);
+        mDisplays.emplace(displayId, std::move(newDisplay));
     } else if (connection == Connection::Disconnected) {
         // The display will later be destroyed by a call to
         // destroyDisplay(). For now we just mark it disconnected.
@@ -209,16 +212,14 @@
 // Display methods
 
 Display::Display(android::Hwc2::Composer& composer,
-                 const std::unordered_set<Capability>& capabilities,
-                 hwc2_display_t id, DisplayType type)
-  : mComposer(composer),
-    mCapabilities(capabilities),
-    mId(id),
-    mIsConnected(false),
-    mType(type)
-{
+                 const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
+                 DisplayType type)
+      : mComposer(composer),
+        mCapabilities(capabilities),
+        mId(id),
+        mIsConnected(false),
+        mType(type) {
     ALOGV("Created display %" PRIu64, id);
-    setConnected(true);
 }
 
 Display::~Display() {
@@ -362,21 +363,10 @@
     return Error::None;
 }
 
-Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
+Error Display::getColorModes(std::vector<ColorMode>* outModes) const
 {
-    std::vector<Hwc2::ColorMode> modes;
-    auto intError = mComposer.getColorModes(mId, &modes);
-    uint32_t numModes = modes.size();
-    auto error = static_cast<Error>(intError);
-    if (error != Error::None) {
-        return error;
-    }
-
-    outModes->resize(numModes);
-    for (size_t i = 0; i < numModes; i++) {
-        (*outModes)[i] = static_cast<android_color_mode_t>(modes[i]);
-    }
-    return Error::None;
+    auto intError = mComposer.getColorModes(mId, outModes);
+    return static_cast<Error>(intError);
 }
 
 std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const
@@ -527,20 +517,18 @@
 }
 
 Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target,
-        const sp<Fence>& acquireFence, android_dataspace_t dataspace)
+        const sp<Fence>& acquireFence, Dataspace dataspace)
 {
     // TODO: Properly encode client target surface damage
     int32_t fenceFd = acquireFence->dup();
     auto intError = mComposer.setClientTarget(mId, slot, target,
-            fenceFd, static_cast<Hwc2::Dataspace>(dataspace),
-            std::vector<Hwc2::IComposerClient::Rect>());
+            fenceFd, dataspace, std::vector<Hwc2::IComposerClient::Rect>());
     return static_cast<Error>(intError);
 }
 
-Error Display::setColorMode(android_color_mode_t mode)
+Error Display::setColorMode(ColorMode mode)
 {
-    auto intError = mComposer.setColorMode(
-            mId, static_cast<Hwc2::ColorMode>(mode));
+    auto intError = mComposer.setColorMode(mId, mode);
     return static_cast<Error>(intError);
 }
 
@@ -777,14 +765,13 @@
     return static_cast<Error>(intError);
 }
 
-Error Layer::setDataspace(android_dataspace_t dataspace)
+Error Layer::setDataspace(Dataspace dataspace)
 {
     if (dataspace == mDataSpace) {
         return Error::None;
     }
     mDataSpace = dataspace;
-    auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
-    auto intError = mComposer.setLayerDataspace(mDisplayId, mId, intDataspace);
+    auto intError = mComposer.setLayerDataspace(mDisplayId, mId, mDataSpace);
     return static_cast<Error>(intError);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e74f00d..9b870e3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -25,6 +25,7 @@
 
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
+#include <ui/GraphicTypes.h>
 #include <ui/HdrCapabilities.h>
 
 #include <utils/Log.h>
@@ -47,6 +48,8 @@
     namespace Hwc2 {
         class Composer;
     }
+
+    class TestableSurfaceFlinger;
 }
 
 namespace HWC2 {
@@ -93,7 +96,7 @@
 
     uint32_t getMaxVirtualDisplayCount() const;
     Error createVirtualDisplay(uint32_t width, uint32_t height,
-            android_pixel_format_t* format, Display** outDisplay);
+            android::ui::PixelFormat* format, Display** outDisplay);
     void destroyDisplay(hwc2_display_t displayId);
 
     void onHotplug(hwc2_display_t displayId, Connection connection);
@@ -125,8 +128,7 @@
 class Display
 {
 public:
-    Display(android::Hwc2::Composer& composer,
-            const std::unordered_set<Capability>& capabilities,
+    Display(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
             hwc2_display_t id, DisplayType type);
     ~Display();
 
@@ -209,7 +211,7 @@
     [[clang::warn_unused_result]] Error getChangedCompositionTypes(
             std::unordered_map<Layer*, Composition>* outTypes);
     [[clang::warn_unused_result]] Error getColorModes(
-            std::vector<android_color_mode_t>* outModes) const;
+            std::vector<android::ui::ColorMode>* outModes) const;
 
     // Doesn't call into the HWC2 device, so no errors are possible
     std::vector<std::shared_ptr<const Config>> getConfigs() const;
@@ -232,8 +234,9 @@
     [[clang::warn_unused_result]] Error setClientTarget(
             uint32_t slot, const android::sp<android::GraphicBuffer>& target,
             const android::sp<android::Fence>& acquireFence,
-            android_dataspace_t dataspace);
-    [[clang::warn_unused_result]] Error setColorMode(android_color_mode_t mode);
+            android::ui::Dataspace dataspace);
+    [[clang::warn_unused_result]] Error setColorMode(
+            android::ui::ColorMode mode);
     [[clang::warn_unused_result]] Error setColorTransform(
             const android::mat4& matrix, android_color_transform_t hint);
     [[clang::warn_unused_result]] Error setOutputBuffer(
@@ -244,8 +247,8 @@
     [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
             uint32_t* outNumRequests);
     [[clang::warn_unused_result]] Error presentOrValidate(uint32_t* outNumTypes,
-                                                 uint32_t* outNumRequests,
-                                                          android::sp<android::Fence>* outPresentFence, uint32_t* state);
+            uint32_t* outNumRequests,
+            android::sp<android::Fence>* outPresentFence, uint32_t* state);
 
     // Other Display methods
 
@@ -262,6 +265,8 @@
     // on this display
     Layer* getLayerById(hwc2_layer_t id) const;
 
+    friend android::TestableSurfaceFlinger;
+
     // Member variables
 
     // These are references to data owned by HWC2::Device, which will outlive
@@ -306,7 +311,7 @@
     [[clang::warn_unused_result]] Error setColor(hwc_color_t color);
     [[clang::warn_unused_result]] Error setCompositionType(Composition type);
     [[clang::warn_unused_result]] Error setDataspace(
-            android_dataspace_t dataspace);
+            android::ui::Dataspace dataspace);
     [[clang::warn_unused_result]] Error setHdrMetadata(const android::HdrMetadata& metadata);
     [[clang::warn_unused_result]] Error setDisplayFrame(
             const android::Rect& frame);
@@ -330,7 +335,7 @@
 
     hwc2_display_t mDisplayId;
     hwc2_layer_t mId;
-    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN;
     android::HdrMetadata mHdrMetadata;
     std::function<void(Layer*)> mLayerDestroyedListener;
 };
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2cafd8e..29e2727 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -179,7 +179,7 @@
 }
 
 status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
-        android_pixel_format_t* format, int32_t *outId) {
+        ui::PixelFormat* format, int32_t *outId) {
     if (mRemainingHwcVirtualDisplays == 0) {
         ALOGE("allocateVirtualDisplay: No remaining virtual displays");
         return NO_MEMORY;
@@ -311,8 +311,8 @@
     return config;
 }
 
-std::vector<android_color_mode_t> HWComposer::getColorModes(int32_t displayId) const {
-    std::vector<android_color_mode_t> modes;
+std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
+    std::vector<ui::ColorMode> modes;
 
     if (!isValidDisplay(displayId)) {
         ALOGE("getColorModes: Attempted to access invalid display %d",
@@ -324,13 +324,13 @@
     if (error != HWC2::Error::None) {
         ALOGE("getColorModes failed for display %d: %s (%d)", displayId,
                 to_string(error).c_str(), static_cast<int32_t>(error));
-        return std::vector<android_color_mode_t>();
+        return std::vector<ui::ColorMode>();
     }
 
     return modes;
 }
 
-status_t HWComposer::setActiveColorMode(int32_t displayId, android_color_mode_t mode) {
+status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode) {
     if (!isValidDisplay(displayId)) {
         ALOGE("setActiveColorMode: Display %d is not valid", displayId);
         return BAD_INDEX;
@@ -387,7 +387,7 @@
 
 status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
-        android_dataspace_t dataspace) {
+        ui::Dataspace dataspace) {
     if (!isValidDisplay(displayId)) {
         return BAD_INDEX;
     }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b75dc6a..6e2e156 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -23,6 +23,7 @@
 #include <sys/types.h>
 
 #include <ui/Fence.h>
+#include <ui/GraphicTypes.h>
 
 #include <utils/BitSet.h>
 #include <utils/Condition.h>
@@ -79,7 +80,7 @@
     // Attempts to allocate a virtual display. If the virtual display is created
     // on the HWC device, outId will contain its HWC ID.
     status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
-            android_pixel_format_t* format, int32_t* outId);
+            ui::PixelFormat* format, int32_t* outId);
 
     // Attempts to create a new layer on this display
     HWC2::Layer* createLayer(int32_t displayId);
@@ -91,7 +92,7 @@
 
     status_t setClientTarget(int32_t displayId, uint32_t slot,
             const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& target, android_dataspace_t dataspace);
+            const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
 
     // Present layers to the display and read releaseFences.
     status_t presentAndGetReleaseFences(int32_t displayId);
@@ -158,9 +159,9 @@
     std::shared_ptr<const HWC2::Display::Config>
             getActiveConfig(int32_t displayId) const;
 
-    std::vector<android_color_mode_t> getColorModes(int32_t displayId) const;
+    std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
 
-    status_t setActiveColorMode(int32_t displayId, android_color_mode_t mode);
+    status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode);
 
     bool isUsingVrComposer() const;
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 3480b24..9a2817d 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -222,7 +222,7 @@
 
         // TODO: Correctly propagate the dataspace from GL composition
         result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
-                hwcBuffer, HAL_DATASPACE_UNKNOWN);
+                hwcBuffer, ui::Dataspace::UNKNOWN);
     }
 
     return result;
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index ac54059..fb6cff5 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -26,6 +26,10 @@
 
 namespace android {
 
+EventControlThread::~EventControlThread() = default;
+
+namespace impl {
+
 EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
       : mSetVSyncEnabled(function) {
     pthread_setname_np(mThread.native_handle(), "EventControlThread");
@@ -67,4 +71,5 @@
     }
 }
 
+} // namespace impl
 } // namespace android
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index 321fb79..9be4e7c 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include <cstddef>
 #include <condition_variable>
+#include <cstddef>
 #include <functional>
 #include <mutex>
 #include <thread>
@@ -30,12 +30,22 @@
 
 class EventControlThread {
 public:
+    virtual ~EventControlThread();
+
+    virtual void setVsyncEnabled(bool enabled) = 0;
+};
+
+namespace impl {
+
+class EventControlThread final : public android::EventControlThread {
+public:
     using SetVSyncEnabledFunction = std::function<void(bool)>;
 
     explicit EventControlThread(SetVSyncEnabledFunction function);
     ~EventControlThread();
 
-    void setVsyncEnabled(bool enabled);
+    // EventControlThread implementation
+    void setVsyncEnabled(bool enabled) override;
 
 private:
     void threadMain();
@@ -51,4 +61,5 @@
     std::thread mThread{&EventControlThread::threadMain, this};
 };
 
+} // namespace impl
 } // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 1f4f5a5..bb9c070 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -217,7 +217,7 @@
             if (timestamp) {
                 // we have a vsync event to dispatch
                 if (mInterceptVSyncs) {
-                    mFlinger.mInterceptor.saveVSyncEvent(timestamp);
+                    mFlinger.mInterceptor->saveVSyncEvent(timestamp);
                 }
                 *event = mVSyncEvent[i];
                 mVSyncEvent[i].header.timestamp = 0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 78dd40b..9d356d8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -42,6 +42,7 @@
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
+#include "BufferLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
 #include "Layer.h"
@@ -121,7 +122,7 @@
     mCurrentState.layerStack = 0;
     mCurrentState.sequence = 0;
     mCurrentState.requested = mCurrentState.active;
-    mCurrentState.dataSpace = HAL_DATASPACE_UNKNOWN;
+    mCurrentState.dataSpace = ui::Dataspace::UNKNOWN;
     mCurrentState.appId = 0;
     mCurrentState.type = 0;
 
@@ -587,8 +588,10 @@
     sp<Layer> parent = mDrawingParent.promote();
     if (parent.get()) {
         auto& parentState = parent->getDrawingState();
-        type = parentState.type;
-        appId = parentState.appId;
+        if (parentState.type >= 0 || parentState.appId >= 0) {
+            type = parentState.type;
+            appId = parentState.appId;
+        }
     }
 
     error = hwcLayer->setInfo(type, appId);
@@ -626,19 +629,14 @@
         transform = Transform(invTransform) * tr * bufferOrientation;
     }
 
-    // STOPSHIP (b/72106793): If we have less than 25% scaling, HWC usually needs to use the rotator
-    // to handle it. However, there is one guaranteed frame of jank when we switch to using the
-    // rotator. In the meantime, we force GL composition instead until we have a better fix for the
-    // HWC issue.
-    bool extremeScaling = abs(t[0][0]) <= 0.25 || abs(t[1][1]) <= 0.25;
-
     // this gives us only the "orientation" component of the transform
     const uint32_t orientation = transform.getOrientation();
-    if (orientation & Transform::ROT_INVALID || extremeScaling) {
+    if (orientation & Transform::ROT_INVALID) {
         // we can only handle simple transformation
         hwcInfo.forceClientComposition = true;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
+        hwcInfo.transform = transform;
         auto error = hwcLayer->setTransform(transform);
         ALOGE_IF(error != HWC2::Error::None,
                  "[%s] Failed to set transform %s: "
@@ -1313,7 +1311,7 @@
     return true;
 }
 
-void Layer::setInfo(uint32_t type, uint32_t appId) {
+void Layer::setInfo(int32_t type, int32_t appId) {
     mCurrentState.appId = appId;
     mCurrentState.type = type;
     mCurrentState.modified = true;
@@ -1329,7 +1327,7 @@
     return true;
 }
 
-bool Layer::setDataSpace(android_dataspace dataSpace) {
+bool Layer::setDataSpace(ui::Dataspace dataSpace) {
     if (mCurrentState.dataSpace == dataSpace) return false;
     mCurrentState.sequence++;
     mCurrentState.dataSpace = dataSpace;
@@ -1338,7 +1336,7 @@
     return true;
 }
 
-android_dataspace Layer::getDataSpace() const {
+ui::Dataspace Layer::getDataSpace() const {
     return mCurrentState.dataSpace;
 }
 
@@ -1434,7 +1432,7 @@
     info.mColor = ds.color;
     info.mFlags = ds.flags;
     info.mPixelFormat = getPixelFormat();
-    info.mDataSpace = getDataSpace();
+    info.mDataSpace = static_cast<android_dataspace>(getDataSpace());
     info.mMatrix[0][0] = ds.active.transform[0][0];
     info.mMatrix[0][1] = ds.active.transform[0][1];
     info.mMatrix[1][0] = ds.active.transform[1][0];
@@ -1492,7 +1490,11 @@
 
     const Layer::State& layerState(getDrawingState());
     const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(hwcId);
-    result.appendFormat("  %10d | ", layerState.z);
+    if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
+        result.appendFormat("  rel %6d | ", layerState.z);
+    } else {
+        result.appendFormat("  %10d | ", layerState.z);
+    }
     result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str());
     const Rect& frame = hwcInfo.displayFrame;
     result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
@@ -1594,6 +1596,12 @@
     return true;
 }
 
+void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->mDrawingParent = newParent;
+    }
+}
+
 bool Layer::reparent(const sp<IBinder>& newParentHandle) {
     if (newParentHandle == nullptr) {
         return false;
@@ -1887,7 +1895,7 @@
 
     layerInfo->set_is_opaque(isOpaque(state));
     layerInfo->set_invalidate(contentDirty);
-    layerInfo->set_dataspace(dataspaceDetails(getDataSpace()));
+    layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
     layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
     LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color());
     LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color());
@@ -1913,6 +1921,33 @@
 
     layerInfo->set_queued_frames(getQueuedFrameCount());
     layerInfo->set_refresh_pending(isBufferLatched());
+    layerInfo->set_window_type(state.type);
+    layerInfo->set_app_id(state.appId);
+}
+
+void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+    writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+
+    const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+
+    const Rect& frame = hwcInfo.displayFrame;
+    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+
+    const FloatRect& crop = hwcInfo.sourceCrop;
+    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+
+    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    layerInfo->set_hwc_transform(transform);
+
+    const int32_t compositionType = static_cast<int32_t>(hwcInfo.compositionType);
+    layerInfo->set_hwc_composition_type(compositionType);
+
+    if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
+        static_cast<BufferLayer*>(this)->isProtected()) {
+        layerInfo->set_is_protected(true);
+    } else {
+        layerInfo->set_is_protected(false);
+    }
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3671a2b..8d2a048 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_LAYER_H
 #define ANDROID_LAYER_H
 
-#include <stdint.h>
 #include <sys/types.h>
 
 #include <utils/RefBase.h>
@@ -35,6 +34,7 @@
 #include <gui/BufferQueue.h>
 
 #include <list>
+#include <cstdint>
 
 #include "Client.h"
 #include "FrameTracker.h"
@@ -66,6 +66,10 @@
 class LayerDebugInfo;
 class LayerBE;
 
+namespace impl {
+class SurfaceInterceptor;
+}
+
 // ---------------------------------------------------------------------------
 
 struct CompositionInfo {
@@ -109,7 +113,8 @@
                 layer(nullptr),
                 forceClientComposition(false),
                 compositionType(HWC2::Composition::Invalid),
-                clearClientTarget(false) {}
+                clearClientTarget(false),
+                transform(HWC2::Transform::None) {}
 
         HWComposer* hwc;
         HWC2::Layer* layer;
@@ -119,6 +124,7 @@
         Rect displayFrame;
         FloatRect sourceCrop;
         HWComposerBufferCache bufferCache;
+        HWC2::Transform transform;
     };
 
     // A layer can be attached to multiple displays when operating in mirror mode
@@ -201,10 +207,10 @@
         // dependent.
         Region activeTransparentRegion;
         Region requestedTransparentRegion;
-        android_dataspace dataSpace;
+        ui::Dataspace dataSpace;
 
-        uint32_t appId;
-        uint32_t type;
+        int32_t appId;
+        int32_t type;
 
         // If non-null, a Surface this Surface's Z-order is interpreted relative to.
         wp<Layer> zOrderRelativeOf;
@@ -279,22 +285,23 @@
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setLayerStack(uint32_t layerStack);
-    bool setDataSpace(android_dataspace dataSpace);
-    android_dataspace getDataSpace() const;
+    bool setDataSpace(ui::Dataspace dataSpace);
+    ui::Dataspace getDataSpace() const;
     uint32_t getLayerStack() const;
     void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
     void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber);
     bool setOverrideScalingMode(int32_t overrideScalingMode);
-    void setInfo(uint32_t type, uint32_t appId);
+    void setInfo(int32_t type, int32_t appId);
     bool reparentChildren(const sp<IBinder>& layer);
+    void setChildrenDrawingParent(const sp<Layer>& layer);
     bool reparent(const sp<IBinder>& newParentHandle);
     bool detachChildren();
 
     // If we have received a new buffer this frame, we will pass its surface
     // damage down to hardware composer. Otherwise, we must send a region with
     // one empty rect.
-    virtual void useSurfaceDamage() = 0;
-    virtual void useEmptyDamage() = 0;
+    virtual void useSurfaceDamage() {}
+    virtual void useEmptyDamage() {}
 
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
@@ -320,7 +327,7 @@
      * pixel format includes an alpha channel) and the "opaque" flag set
      * on the layer.  It does not examine the current plane alpha value.
      */
-    virtual bool isOpaque(const Layer::State& s) const = 0;
+    virtual bool isOpaque(const Layer::State&) const { return false; }
 
     /*
      * isSecure - true if this surface is secure, that is if it prevents
@@ -344,13 +351,16 @@
     /*
      * isFixedSize - true if content has a fixed size
      */
-    virtual bool isFixedSize() const = 0;
+    virtual bool isFixedSize() const { return true; }
+
 
     bool isPendingRemoval() const { return mPendingRemoval; }
 
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
+    void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+
 protected:
     /*
      * onDraw - draws the surface.
@@ -359,7 +369,7 @@
                         bool useIdentityTransform) const = 0;
 
 public:
-    virtual void setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
+    virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
 
     void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
     void forceClientComposition(int32_t hwcId);
@@ -379,27 +389,30 @@
      */
     virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
 
-    virtual void abandon() = 0;
+    virtual void abandon() {}
 
-    virtual bool shouldPresentNow(const DispSync& dispSync) const = 0;
-    virtual void setTransformHint(uint32_t orientation) const = 0;
+    virtual bool shouldPresentNow(const DispSync& /*dispSync*/) const { return false; }
+    virtual void setTransformHint(uint32_t /*orientation*/) const { }
 
     /*
      * called before composition.
      * returns true if the layer has pending updates.
      */
-    virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
+    virtual bool onPreComposition(nsecs_t /*refreshStartTime*/) { return true; }
 
     /*
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
      */
-    virtual bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
-                                   const std::shared_ptr<FenceTime>& presentFence,
-                                   const CompositorTiming& compositorTiming) = 0;
+    virtual bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+                                   const std::shared_ptr<FenceTime>& /*presentFence*/,
+                                   const CompositorTiming& /*compositorTiming*/) {
+        return false;
+    }
 
     // If a buffer was replaced this frame, release the former buffer
-    virtual void releasePendingBuffer(nsecs_t dequeueReadyTime) = 0;
+    virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+
 
     /*
      * draw - performs some global clipping optimizations
@@ -445,8 +458,11 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    virtual Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
-    virtual bool isBufferLatched() const = 0;
+    virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
+        return {};
+    }
+
+    virtual bool isBufferLatched() const { return false; }
 
     bool isPotentialCursor() const { return mPotentialCursor; }
     /*
@@ -519,13 +535,15 @@
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
 
-    virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) = 0;
+    virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
+        return {};
+    }
 
     void onDisconnect();
     void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
                                   FrameEventHistoryDelta* outDelta);
 
-    virtual bool getTransformToDisplayInverse() const = 0;
+    virtual bool getTransformToDisplayInverse() const { return false; }
 
     Transform getTransform() const;
 
@@ -583,7 +601,7 @@
 
     virtual void onFirstRef();
 
-    friend class SurfaceInterceptor;
+    friend class impl::SurfaceInterceptor;
 
     void commitTransaction(const State& stateToCommit);
 
@@ -649,7 +667,7 @@
     // Returns mCurrentScaling mode (originating from the
     // Client) or mOverrideScalingMode mode (originating from
     // the Surface Controller) if set.
-    virtual uint32_t getEffectiveScalingMode() const = 0;
+    virtual uint32_t getEffectiveScalingMode() const { return 0; }
 
 public:
     /*
@@ -670,8 +688,8 @@
 
     sp<IBinder> getHandle();
     const String8& getName() const;
-    virtual void notifyAvailableFrames() = 0;
-    virtual PixelFormat getPixelFormat() const = 0;
+    virtual void notifyAvailableFrames() {}
+    virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
     bool getPremultipledAlpha() const;
 
 protected:
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 6a33148..cc39550 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -37,6 +37,13 @@
     rectProto->set_right(rect.right);
 }
 
+void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
+    rectProto->set_left(rect.left);
+    rectProto->set_top(rect.top);
+    rectProto->set_bottom(rect.bottom);
+    rectProto->set_right(rect.right);
+}
+
 void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
     colorProto->set_r(color.r);
     colorProto->set_g(color.g);
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 45a0b5d..860da63 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -29,6 +29,7 @@
 class LayerProtoHelper {
 public:
     static void writeToProto(const Rect& rect, RectProto* rectProto);
+    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
     static void writeToProto(const Region& region, RegionProto* regionProto);
     static void writeToProto(const half4 color, ColorProto* colorProto);
     static void writeToProto(const Transform& transform, TransformProto* transformProto);
@@ -36,4 +37,4 @@
 };
 
 } // namespace surfaceflinger
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
new file mode 100644
index 0000000..38ea6ed
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "LayerStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerStats.h"
+#include "DisplayHardware/HWComposer.h"
+#include "ui/DebugUtils.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void LayerStats::enable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mEnabled) return;
+    mLayerShapeStatsMap.clear();
+    mEnabled = true;
+    ALOGD("Logging enabled");
+}
+
+void LayerStats::disable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mEnabled) return;
+    mEnabled = false;
+    ALOGD("Logging disabled");
+}
+
+void LayerStats::clear() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    mLayerShapeStatsMap.clear();
+    ALOGD("Cleared current layer stats");
+}
+
+bool LayerStats::isEnabled() {
+    return mEnabled;
+}
+
+void LayerStats::traverseLayerTreeStatsLocked(
+        std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+        const LayerProtoParser::LayerGlobal* layerGlobal, std::vector<std::string>& layerShapeVec) {
+    for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) {
+        if (!layer) continue;
+        traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal, layerShapeVec);
+        std::string key = "";
+        base::StringAppendF(&key, ",%s", layer->type.c_str());
+        base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
+        base::StringAppendF(&key, ",%d", layer->isProtected);
+        base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
+        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+        base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
+        base::StringAppendF(&key, ",%s",
+                            destinationLocation(layer->hwcFrame.left, layerGlobal->resolution[0],
+                                                true));
+        base::StringAppendF(&key, ",%s",
+                            destinationLocation(layer->hwcFrame.top, layerGlobal->resolution[1],
+                                                false));
+        base::StringAppendF(&key, ",%s",
+                            destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                            layerGlobal->resolution[0], true));
+        base::StringAppendF(&key, ",%s",
+                            destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                            layerGlobal->resolution[1], false));
+        base::StringAppendF(&key, ",%s", scaleRatioWH(layer.get()).c_str());
+        base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
+
+        layerShapeVec.push_back(key);
+        ALOGV("%s", key.c_str());
+    }
+}
+
+void LayerStats::logLayerStats(const LayersProto& layersProto) {
+    ATRACE_CALL();
+    ALOGV("Logging");
+    auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
+    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    std::vector<std::string> layerShapeVec;
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal, layerShapeVec);
+
+    std::string layerShapeKey =
+            base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
+                               layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
+                               layerTransform(layerGlobal.globalTransform));
+    ALOGV("%s", layerShapeKey.c_str());
+
+    std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
+    for (auto const& s : layerShapeVec) {
+        layerShapeKey += s;
+    }
+
+    mLayerShapeStatsMap[layerShapeKey]++;
+}
+
+void LayerStats::dump(String8& result) {
+    ATRACE_CALL();
+    ALOGD("Dumping");
+    std::lock_guard<std::mutex> lock(mMutex);
+    result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
+    result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
+    result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
+    for (auto& u : mLayerShapeStatsMap) {
+        result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+    }
+}
+
+const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
+    static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
+    int32_t ratio = location * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isHorizontal) {
+        // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
+        if (ratio > 6) return "3/4";
+        // use index 0, 2, 4, 6
+        return locationArray[ratio & ~1];
+    }
+    if (ratio > 7) return "7/8";
+    return locationArray[ratio];
+}
+
+const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
+    static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
+    int32_t ratio = size * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isWidth) {
+        // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
+        if (ratio > 6) return "1";
+        // use index 1, 3, 5, 7
+        return sizeArray[ratio | 1];
+    }
+    if (ratio > 7) return "1";
+    return sizeArray[ratio];
+}
+
+const char* LayerStats::layerTransform(int32_t transform) {
+    return getTransformName(static_cast<hwc_transform_t>(transform));
+}
+
+const char* LayerStats::layerCompositionType(int32_t compositionType) {
+    return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
+}
+
+const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
+    return decodePixelFormat(pixelFormat).c_str();
+}
+
+std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
+    if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
+    std::string ret = "";
+    if (isRotated(layer->hwcTransform)) {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+    } else {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+    }
+    return ret;
+}
+
+const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
+    // Make scale buckets from <1/64 to >= 16, to avoid floating point
+    // calculation, x64 on destinationScale first
+    int32_t scale = destinationScale * 64 / sourceScale;
+    if (!scale) return "<1/64";
+    if (scale < 2) return "1/64";
+    if (scale < 4) return "1/32";
+    if (scale < 8) return "1/16";
+    if (scale < 16) return "1/8";
+    if (scale < 32) return "1/4";
+    if (scale < 64) return "1/2";
+    if (scale < 128) return "1";
+    if (scale < 256) return "2";
+    if (scale < 512) return "4";
+    if (scale < 1024) return "8";
+    return ">=16";
+}
+
+const char* LayerStats::alpha(float a) {
+    if (a == 1.0f) return "1.0";
+    if (a > 0.9f) return "0.99";
+    if (a > 0.8f) return "0.9";
+    if (a > 0.7f) return "0.8";
+    if (a > 0.6f) return "0.7";
+    if (a > 0.5f) return "0.6";
+    if (a > 0.4f) return "0.5";
+    if (a > 0.3f) return "0.4";
+    if (a > 0.2f) return "0.3";
+    if (a > 0.1f) return "0.2";
+    if (a > 0.0f) return "0.1";
+    return "0.0";
+}
+
+bool LayerStats::isRotated(int32_t transform) {
+    return transform & HWC_TRANSFORM_ROT_90;
+}
+
+bool LayerStats::isVFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_V;
+}
+
+bool LayerStats::isHFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_H;
+}
+
+}  // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
new file mode 100644
index 0000000..7871fc6
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <layerproto/LayerProtoHeader.h>
+#include <layerproto/LayerProtoParser.h>
+#include <mutex>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class LayerStats {
+public:
+    void enable();
+    void disable();
+    void clear();
+    bool isEnabled();
+    void logLayerStats(const LayersProto& layersProto);
+    void dump(String8& result);
+
+private:
+    // Traverse layer tree to get all visible layers' stats
+    void traverseLayerTreeStatsLocked(
+            std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+            const LayerProtoParser::LayerGlobal* layerGlobal,
+            std::vector<std::string>& layerShapeVec);
+    // Convert layer's top-left position into 8x8 percentage of the display
+    static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
+    // Convert layer's size into 8x8 percentage of the display
+    static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
+    // Return the name of the transform
+    static const char* layerTransform(int32_t transform);
+    // Return the name of the composition type
+    static const char* layerCompositionType(int32_t compositionType);
+    // Return the name of the pixel format
+    static const char* layerPixelFormat(int32_t pixelFormat);
+    // Calculate scale ratios of layer's width/height with rotation information
+    static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
+    // Calculate scale ratio from source to destination and convert to string
+    static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+    // Bucket the alpha into designed buckets
+    static const char* alpha(float a);
+    // Return whether the original buffer is rotated in final composition
+    static bool isRotated(int32_t transform);
+    // Return whether the original buffer is V-flipped in final composition
+    static bool isVFlipped(int32_t transform);
+    // Return whether the original buffer is H-flipped in final composition
+    static bool isHFlipped(int32_t transform);
+
+    bool mEnabled = false;
+    // Protect mLayersStatsMap
+    std::mutex mMutex;
+    // Hashmap for tracking the frame(layer shape) stats
+    // KEY is a concatenation of all layers' properties within a frame
+    // VALUE is the number of times this particular set has been scanned out
+    std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
+};
+
+}  // namespace android
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index 5a6ff4d..056d381 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -24,6 +24,7 @@
 #include <utils/Timers.h>
 #include <utils/threads.h>
 
+#include <gui/DisplayEventReceiver.h>
 #include <gui/IDisplayEventConnection.h>
 
 #include "EventThread.h"
@@ -45,6 +46,12 @@
 
 // ---------------------------------------------------------------------------
 
+MessageQueue::~MessageQueue() = default;
+
+// ---------------------------------------------------------------------------
+
+namespace impl {
+
 void MessageQueue::Handler::dispatchRefresh() {
     if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
         mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
@@ -72,17 +79,13 @@
 
 // ---------------------------------------------------------------------------
 
-MessageQueue::MessageQueue() {}
-
-MessageQueue::~MessageQueue() {}
-
 void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
     mFlinger = flinger;
     mLooper = new Looper(true);
     mHandler = new Handler(*this);
 }
 
-void MessageQueue::setEventThread(EventThread* eventThread) {
+void MessageQueue::setEventThread(android::EventThread* eventThread) {
     if (mEventThread == eventThread) {
         return;
     }
@@ -159,4 +162,5 @@
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace impl
+} // namespace android
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index dcfc716..90d1c72 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -25,7 +25,7 @@
 #include <utils/Timers.h>
 #include <utils/threads.h>
 
-#include <gui/DisplayEventReceiver.h>
+#include <gui/IDisplayEventConnection.h>
 #include <private/gui/BitTube.h>
 
 #include "Barrier.h"
@@ -34,7 +34,6 @@
 
 namespace android {
 
-class IDisplayEventConnection;
 class EventThread;
 class SurfaceFlinger;
 
@@ -77,6 +76,27 @@
 // ---------------------------------------------------------------------------
 
 class MessageQueue {
+public:
+    enum {
+        INVALIDATE = 0,
+        REFRESH = 1,
+    };
+
+    virtual ~MessageQueue();
+
+    virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
+    virtual void setEventThread(EventThread* events) = 0;
+    virtual void waitMessage() = 0;
+    virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
+    virtual void invalidate() = 0;
+    virtual void refresh() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+namespace impl {
+
+class MessageQueue final : public android::MessageQueue {
     class Handler : public MessageHandler {
         enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
         MessageQueue& mQueue;
@@ -93,7 +113,7 @@
 
     sp<SurfaceFlinger> mFlinger;
     sp<Looper> mLooper;
-    EventThread* mEventThread;
+    android::EventThread* mEventThread;
     sp<IDisplayEventConnection> mEvents;
     gui::BitTube mEventTube;
     sp<Handler> mHandler;
@@ -102,27 +122,22 @@
     int eventReceiver(int fd, int events);
 
 public:
-    enum {
-        INVALIDATE = 0,
-        REFRESH = 1,
-    };
+    ~MessageQueue() override = default;
+    void init(const sp<SurfaceFlinger>& flinger) override;
+    void setEventThread(android::EventThread* events) override;
 
-    MessageQueue();
-    ~MessageQueue();
-    void init(const sp<SurfaceFlinger>& flinger);
-    void setEventThread(EventThread* events);
-
-    void waitMessage();
-    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0);
+    void waitMessage() override;
+    status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override;
 
     // sends INVALIDATE message at next VSYNC
-    void invalidate();
+    void invalidate() override;
     // sends REFRESH message at next VSYNC
-    void refresh();
+    void refresh() override;
 };
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace impl
+} // namespace android
 
 #endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index fa4df83..bf0707f 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -1,7 +1,11 @@
 #pragma once
 
+#include <ui/GraphicTypes.h>
+
 #include "Transform.h"
 
+#include <functional>
+
 namespace android {
 
 class RenderArea {
@@ -22,11 +26,13 @@
     virtual bool needsFiltering() const = 0;
     virtual Rect getSourceCrop() const = 0;
 
+    virtual void render(std::function<void()> drawLayers) { drawLayers(); }
+
     int getReqHeight() const { return mReqHeight; };
     int getReqWidth() const { return mReqWidth; };
     Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
     virtual bool getWideColorSupport() const = 0;
-    virtual android_color_mode_t getActiveColorMode() const = 0;
+    virtual ui::ColorMode getActiveColorMode() const = 0;
 
     status_t updateDimensions();
 
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index ea7dc2f..1eda900 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -109,6 +109,8 @@
 namespace impl {
 // ---------------------------------------------------------------------------
 
+using ui::Dataspace;
+
 GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
       : mVpWidth(0), mVpHeight(0), mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
@@ -214,11 +216,11 @@
     mState.setY410BT2020(enable);
 }
 
-void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
+void GLES20RenderEngine::setSourceDataSpace(Dataspace source) {
     mDataSpace = source;
 }
 
-void GLES20RenderEngine::setOutputDataSpace(android_dataspace dataspace) {
+void GLES20RenderEngine::setOutputDataSpace(Dataspace dataspace) {
     mOutputDataSpace = dataspace;
 }
 
@@ -301,14 +303,14 @@
                           mesh.getByteStride(), mesh.getPositions());
 
     // DISPLAY_P3 is the only supported wide color output
-    if (mPlatformHasWideColor && mOutputDataSpace == HAL_DATASPACE_DISPLAY_P3) {
+    if (mPlatformHasWideColor && mOutputDataSpace == Dataspace::DISPLAY_P3) {
         Description wideColorState = mState;
-        switch (int(mDataSpace)) {
-            case HAL_DATASPACE_DISPLAY_P3:
+        switch (mDataSpace) {
+            case Dataspace::DISPLAY_P3:
                 // input matches output
                 break;
-            case HAL_DATASPACE_BT2020_PQ:
-            case HAL_DATASPACE_BT2020_ITU_PQ:
+            case Dataspace::BT2020_PQ:
+            case Dataspace::BT2020_ITU_PQ:
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
                 wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
                 wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
@@ -317,7 +319,7 @@
             default:
                 // treat all other dataspaces as sRGB
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                if ((mDataSpace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_LINEAR) {
+                if ((mDataSpace & Dataspace::TRANSFER_MASK) & Dataspace::TRANSFER_LINEAR) {
                     wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
                 } else {
                     wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
@@ -350,8 +352,8 @@
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
     result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
-                        dataspaceDetails(mDataSpace).c_str(),
-                        dataspaceDetails(mOutputDataSpace).c_str());
+                        dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+                        dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index db3f792..99da19d 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -73,14 +73,14 @@
 
     // Color management related functions and state
     void setSourceY410BT2020(bool enable) override;
-    void setSourceDataSpace(android_dataspace source) override;
-    void setOutputDataSpace(android_dataspace dataspace) override;
+    void setSourceDataSpace(ui::Dataspace source) override;
+    void setOutputDataSpace(ui::Dataspace dataspace) override;
 
     // Current dataspace of layer being rendered
-    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
+    ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
 
     // Current output dataspace of the render engine
-    android_dataspace mOutputDataSpace = HAL_DATASPACE_UNKNOWN;
+    ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
 
     // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
     const bool mPlatformHasWideColor = false;
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 7a43ea9..6a34981 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -305,15 +305,24 @@
 
         if (needs.hasToneMapping()) {
             fs << R"__SHADER__(
-                float ToneMapChannel(const float color) {
+                float CalculateY(const vec3 color) {
+                    // BT2020 standard uses the unadjusted KR = 0.2627,
+                    // KB = 0.0593 luminance interpretation for RGB conversion.
+                    return color.r * 0.262700 + color.g * 0.677998 +
+                            color.b * 0.059302;
+                }
+                vec3 ToneMap(const vec3 color) {
                     const float maxLumi = 10000.0;
                     const float maxMasteringLumi = 1000.0;
                     const float maxContentLumi = 1000.0;
                     const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
                     const float maxOutLumi = 500.0;
 
+                    // Calculate Y value in XYZ color space.
+                    float colorY = CalculateY(color);
+
                     // convert to nits first
-                    float nits = color * maxLumi;
+                    float nits = colorY * maxLumi;
 
                     // clamp to max input luminance
                     nits = clamp(nits, 0.0, maxInLumi);
@@ -360,12 +369,8 @@
                     }
 
                     // convert back to [0.0, 1.0]
-                    return nits / maxOutLumi;
-                }
-
-                vec3 ToneMap(const vec3 color) {
-                    return vec3(ToneMapChannel(color.r), ToneMapChannel(color.g),
-                                ToneMapChannel(color.b));
+                    float targetY = nits / maxOutLumi;
+                    return color * (targetY / max(1e-6, colorY));
                 }
             )__SHADER__";
         } else {
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index d140574..f78b230 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -119,8 +119,8 @@
 
     // wide color support
     virtual void setSourceY410BT2020(bool enable) = 0;
-    virtual void setSourceDataSpace(android_dataspace source) = 0;
-    virtual void setOutputDataSpace(android_dataspace dataspace) = 0;
+    virtual void setSourceDataSpace(ui::Dataspace source) = 0;
+    virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
 
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/Surface.cpp
index 3c29e4b..0d20f1f 100644
--- a/services/surfaceflinger/RenderEngine/Surface.cpp
+++ b/services/surfaceflinger/RenderEngine/Surface.cpp
@@ -66,7 +66,7 @@
 
 EGLint Surface::queryConfig(EGLint attrib) const {
     EGLint value;
-    if (!eglGetConfigAttrib(mEGLConfig, mEGLConfig, attrib, &value)) {
+    if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) {
         value = 0;
     }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cb410a1..ea75958 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -61,20 +61,21 @@
 #include <private/android_filesystem_config.h>
 #include <private/gui/SyncFeatures.h>
 
+#include "BufferLayer.h"
 #include "Client.h"
-#include "clz.h"
+#include "ColorLayer.h"
 #include "Colorizer.h"
+#include "ContainerLayer.h"
 #include "DdmConnection.h"
-#include "DisplayDevice.h"
 #include "DispSync.h"
+#include "DisplayDevice.h"
 #include "EventControlThread.h"
 #include "EventThread.h"
 #include "Layer.h"
-#include "BufferLayer.h"
 #include "LayerVector.h"
-#include "ColorLayer.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
+#include "clz.h"
 
 #include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/FramebufferSurface.h"
@@ -103,6 +104,8 @@
 
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ui::ColorMode;
+using ui::Dataspace;
 
 namespace {
 class ConditionalLock {
@@ -153,6 +156,32 @@
     return std::string(value) == "true";
 }
 
+NativeWindowSurface::~NativeWindowSurface() = default;
+
+namespace impl {
+
+class NativeWindowSurface final : public android::NativeWindowSurface {
+public:
+    static std::unique_ptr<android::NativeWindowSurface> create(
+            const sp<IGraphicBufferProducer>& producer) {
+        return std::make_unique<NativeWindowSurface>(producer);
+    }
+
+    explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
+          : surface(new Surface(producer, false)) {}
+
+    ~NativeWindowSurface() override = default;
+
+private:
+    sp<ANativeWindow> getNativeWindow() const override { return surface; }
+
+    void preallocateBuffers() override { surface->allocateBuffers(); }
+
+    sp<Surface> surface;
+};
+
+} // namespace impl
+
 SurfaceFlingerBE::SurfaceFlingerBE()
       : mHwcServiceName(getHwcServiceName()),
         mRenderEngine(nullptr),
@@ -162,7 +191,7 @@
         mComposerSequenceId(0) {
 }
 
-SurfaceFlinger::SurfaceFlinger()
+SurfaceFlinger::SurfaceFlinger(SurfaceFlinger::SkipInitializationTag)
       : BnSurfaceComposer(),
         mTransactionFlags(0),
         mTransactionPending(false),
@@ -185,7 +214,6 @@
         mLastTransactionTime(0),
         mBootFinished(false),
         mForceFullDamage(false),
-        mInterceptor(this),
         mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
@@ -194,7 +222,10 @@
         mNumLayers(0),
         mVrFlingerRequestsDisplay(false),
         mMainThreadId(std::this_thread::get_id()),
-        mCreateBufferQueue(&BufferQueue::createBufferQueue) {
+        mCreateBufferQueue(&BufferQueue::createBufferQueue),
+        mCreateNativeWindowSurface(&impl::NativeWindowSurface::create) {}
+
+SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
     ALOGI("SurfaceFlinger is starting");
 
     vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
@@ -259,6 +290,11 @@
     mLayerTripleBufferingDisabled = atoi(value);
     ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
 
+    // TODO (b/74616334): Reduce the default value once we isolate the leak
+    const size_t defaultListSize = 4 * MAX_LAYERS;
+    auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
+    mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
     // comes online to attempt to read the property. The property is
@@ -276,7 +312,7 @@
 
 void SurfaceFlinger::onFirstRef()
 {
-    mEventQueue.init(this);
+    mEventQueue->init(this);
 }
 
 SurfaceFlinger::~SurfaceFlinger()
@@ -342,7 +378,7 @@
     DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
     info.displayName = displayName;
     mCurrentState.displays.add(token, info);
-    mInterceptor.saveDisplayCreation(info);
+    mInterceptor->saveDisplayCreation(info);
     return token;
 }
 
@@ -360,7 +396,7 @@
         ALOGE("destroyDisplay called for non-virtual display");
         return;
     }
-    mInterceptor.saveDisplayDeletion(info.displayId);
+    mInterceptor->saveDisplayDeletion(info.displayId);
     mCurrentState.displays.removeItemsAt(idx);
     setTransactionFlags(eDisplayTransactionNeeded);
 }
@@ -582,9 +618,10 @@
     mSfEventThreadSource =
             std::make_unique<DispSyncSource>(&mPrimaryDispSync,
                                              SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+
     mSFEventThread = std::make_unique<impl::EventThread>(mSfEventThreadSource.get(), *this, true,
                                                          "sfEventThread");
-    mEventQueue.setEventThread(mSFEventThread.get());
+    mEventQueue->setEventThread(mSFEventThread.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
     getBE().mRenderEngine =
@@ -631,9 +668,8 @@
         }
     }
 
-    mEventControlThread = std::make_unique<EventControlThread>([this](bool enabled) {
-        setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled);
-    });
+    mEventControlThread = std::make_unique<impl::EventControlThread>(
+            [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
 
     // initialize our drawing state
     mDrawingState = mCurrentState;
@@ -912,7 +948,7 @@
     return NO_ERROR;
 }
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<android_color_mode_t>* outColorModes) {
+        Vector<ColorMode>* outColorModes) {
     if ((outColorModes == nullptr) || (display.get() == nullptr)) {
         return BAD_VALUE;
     }
@@ -933,7 +969,7 @@
         return type;
     }
 
-    std::vector<android_color_mode_t> modes;
+    std::vector<ColorMode> modes;
     {
         ConditionalLock _l(mStateLock,
                 std::this_thread::get_id() != mMainThreadId);
@@ -945,18 +981,18 @@
     return NO_ERROR;
 }
 
-android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
     sp<const DisplayDevice> device(getDisplayDevice(display));
     if (device != nullptr) {
         return device->getActiveColorMode();
     }
-    return static_cast<android_color_mode_t>(BAD_VALUE);
+    return static_cast<ColorMode>(BAD_VALUE);
 }
 
 void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
-        android_color_mode_t mode) {
+        ColorMode mode) {
     int32_t type = hw->getDisplayType();
-    android_color_mode_t currentMode = hw->getActiveColorMode();
+    ColorMode currentMode = hw->getActiveColorMode();
 
     if (mode == currentMode) {
         return;
@@ -976,20 +1012,20 @@
 
 
 status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
-        android_color_mode_t colorMode) {
+        ColorMode colorMode) {
     class MessageSetActiveColorMode: public MessageBase {
         SurfaceFlinger& mFlinger;
         sp<IBinder> mDisplay;
-        android_color_mode_t mMode;
+        ColorMode mMode;
     public:
         MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
-                               android_color_mode_t mode) :
+                               ColorMode mode) :
             mFlinger(flinger), mDisplay(disp) { mMode = mode; }
         virtual bool handler() {
-            Vector<android_color_mode_t> modes;
+            Vector<ColorMode> modes;
             mFlinger.getDisplayColorModes(mDisplay, &modes);
             bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
-            if (mMode < 0 || !exists) {
+            if (mMode < ColorMode::NATIVE || !exists) {
                 ALOGE("Attempt to set invalid active color mode %s (%d) for display %p",
                       decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
                 return true;
@@ -1073,10 +1109,10 @@
                         std::make_unique<impl::EventThread>(mVSyncInjector.get(), *this, false,
                                                             "injEventThread");
             }
-            mEventQueue.setEventThread(mInjectorEventThread.get());
+            mEventQueue->setEventThread(mInjectorEventThread.get());
         } else {
             ALOGV("VSync Injections disabled");
-            mEventQueue.setEventThread(mSFEventThread.get());
+            mEventQueue->setEventThread(mSFEventThread.get());
         }
 
         mInjectVSyncs = enable;
@@ -1141,30 +1177,30 @@
 // ----------------------------------------------------------------------------
 
 void SurfaceFlinger::waitForEvent() {
-    mEventQueue.waitMessage();
+    mEventQueue->waitMessage();
 }
 
 void SurfaceFlinger::signalTransaction() {
-    mEventQueue.invalidate();
+    mEventQueue->invalidate();
 }
 
 void SurfaceFlinger::signalLayerUpdate() {
-    mEventQueue.invalidate();
+    mEventQueue->invalidate();
 }
 
 void SurfaceFlinger::signalRefresh() {
     mRefreshPending = true;
-    mEventQueue.refresh();
+    mEventQueue->refresh();
 }
 
 status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t /* flags */) {
-    return mEventQueue.postMessage(msg, reltime);
+    return mEventQueue->postMessage(msg, reltime);
 }
 
 status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t /* flags */) {
-    status_t res = mEventQueue.postMessage(msg, reltime);
+    status_t res = mEventQueue->postMessage(msg, reltime);
     if (res == NO_ERROR) {
         msg->wait();
     }
@@ -1449,6 +1485,7 @@
     setUpHWComposer();
     doDebugFlashRegions();
     doTracing("handleRefresh");
+    logLayerStats();
     doComposition();
     postComposition(refreshStartTime);
 
@@ -1518,6 +1555,25 @@
     }
 }
 
+void SurfaceFlinger::logLayerStats() {
+    ATRACE_CALL();
+    if (CC_UNLIKELY(mLayerStats.isEnabled())) {
+        int32_t hwcId = -1;
+        for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
+            const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
+            if (displayDevice->isPrimary()) {
+                hwcId = displayDevice->getHwcDisplayId();
+                break;
+            }
+        }
+        if (hwcId < 0) {
+            ALOGE("LayerStats: Hmmm, no primary display?");
+            return;
+        }
+        mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+    }
+}
+
 void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
@@ -1782,55 +1838,56 @@
 
 // pickColorMode translates a given dataspace into the best available color mode.
 // Currently only support sRGB and Display-P3.
-android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
+ColorMode SurfaceFlinger::pickColorMode(Dataspace dataSpace) const {
     if (mForceNativeColorMode) {
-        return HAL_COLOR_MODE_NATIVE;
+        return ColorMode::NATIVE;
     }
 
     switch (dataSpace) {
         // treat Unknown as regular SRGB buffer, since that's what the rest of the
         // system expects.
-        case HAL_DATASPACE_UNKNOWN:
-        case HAL_DATASPACE_SRGB:
-        case HAL_DATASPACE_V0_SRGB:
-            return HAL_COLOR_MODE_SRGB;
+        case Dataspace::UNKNOWN:
+        case Dataspace::SRGB:
+        case Dataspace::V0_SRGB:
+            return ColorMode::SRGB;
             break;
 
-        case HAL_DATASPACE_DISPLAY_P3:
-            return HAL_COLOR_MODE_DISPLAY_P3;
+        case Dataspace::DISPLAY_P3:
+            return ColorMode::DISPLAY_P3;
             break;
 
         default:
             // TODO (courtneygo): Do we want to assert an error here?
-            ALOGE("No color mode mapping for %s (%#x)", dataspaceDetails(dataSpace).c_str(),
+            ALOGE("No color mode mapping for %s (%#x)",
+                  dataspaceDetails(static_cast<android_dataspace>(dataSpace)).c_str(),
                   dataSpace);
-            return HAL_COLOR_MODE_SRGB;
+            return ColorMode::SRGB;
             break;
     }
 }
 
-android_dataspace SurfaceFlinger::bestTargetDataSpace(
-        android_dataspace a, android_dataspace b, bool hasHdr) const {
+Dataspace SurfaceFlinger::bestTargetDataSpace(
+        Dataspace a, Dataspace b, bool hasHdr) const {
     // Only support sRGB and Display-P3 right now.
-    if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
-        return HAL_DATASPACE_DISPLAY_P3;
+    if (a == Dataspace::DISPLAY_P3 || b == Dataspace::DISPLAY_P3) {
+        return Dataspace::DISPLAY_P3;
     }
-    if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) {
-        return HAL_DATASPACE_DISPLAY_P3;
+    if (a == Dataspace::V0_SCRGB_LINEAR || b == Dataspace::V0_SCRGB_LINEAR) {
+        return Dataspace::DISPLAY_P3;
     }
-    if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
-        return HAL_DATASPACE_DISPLAY_P3;
+    if (a == Dataspace::V0_SCRGB || b == Dataspace::V0_SCRGB) {
+        return Dataspace::DISPLAY_P3;
     }
     if (!hasHdr) {
-        if (a == HAL_DATASPACE_BT2020_PQ || b == HAL_DATASPACE_BT2020_PQ) {
-            return HAL_DATASPACE_DISPLAY_P3;
+        if (a == Dataspace::BT2020_PQ || b == Dataspace::BT2020_PQ) {
+            return Dataspace::DISPLAY_P3;
         }
-        if (a == HAL_DATASPACE_BT2020_ITU_PQ || b == HAL_DATASPACE_BT2020_ITU_PQ) {
-            return HAL_DATASPACE_DISPLAY_P3;
+        if (a == Dataspace::BT2020_ITU_PQ || b == Dataspace::BT2020_ITU_PQ) {
+            return Dataspace::DISPLAY_P3;
         }
     }
 
-    return HAL_DATASPACE_V0_SRGB;
+    return Dataspace::V0_SRGB;
 }
 
 void SurfaceFlinger::setUpHWComposer() {
@@ -1905,13 +1962,14 @@
             continue;
         }
         if (colorMatrix != mPreviousColorMatrix) {
+            displayDevice->setColorTransform(colorMatrix);
             status_t result = getBE().mHwc->setColorTransform(hwcId, colorMatrix);
             ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
                     "display %zd: %d", displayId, result);
         }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            if ((layer->getDataSpace() == HAL_DATASPACE_BT2020_PQ ||
-                 layer->getDataSpace() == HAL_DATASPACE_BT2020_ITU_PQ) &&
+            if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
+                 layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
                     !displayDevice->getHdrSupport()) {
                 layer->forceClientComposition(hwcId);
             }
@@ -1926,15 +1984,15 @@
         }
 
         if (hasWideColorDisplay) {
-            android_color_mode newColorMode;
-            android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB;
+            ColorMode newColorMode;
+            Dataspace newDataSpace = Dataspace::V0_SRGB;
 
             for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
                 newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace,
                         displayDevice->getHdrSupport());
                 ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
-                      layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(),
-                      layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace);
+                      layer->getName().string(), dataspaceDetails(static_cast<android_dataspace>(layer->getDataSpace())).c_str(),
+                      layer->getDataSpace(), dataspaceDetails(static_cast<android_dataspace>(newDataSpace)).c_str(), newDataSpace);
             }
             newColorMode = pickColorMode(newDataSpace);
 
@@ -2073,7 +2131,7 @@
 }
 
 DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
-        HWC2::Connection connection) const {
+                                                                HWC2::Connection connection) const {
     // Figure out whether the event is for the primary display or an
     // external display by matching the Hwc display id against one for a
     // connected display. If we did not find a match, we then check what
@@ -2114,23 +2172,23 @@
         getBE().mHwc->onHotplug(event.display, displayType, event.connection);
 
         if (event.connection == HWC2::Connection::Connected) {
-            ALOGV("Creating built in display %d", displayType);
-            ALOGW_IF(mBuiltinDisplays[displayType],
-                    "Overwriting display token for display type %d", displayType);
-            mBuiltinDisplays[displayType] = new BBinder();
-            // All non-virtual displays are currently considered secure.
-            DisplayDeviceState info(displayType, true);
-            info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
-                    "Built-in Screen" : "External Screen";
-            mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
-            mInterceptor.saveDisplayCreation(info);
+            if (!mBuiltinDisplays[displayType].get()) {
+                ALOGV("Creating built in display %d", displayType);
+                mBuiltinDisplays[displayType] = new BBinder();
+                // All non-virtual displays are currently considered secure.
+                DisplayDeviceState info(displayType, true);
+                info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
+                        "Built-in Screen" : "External Screen";
+                mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
+                mInterceptor->saveDisplayCreation(info);
+            }
         } else {
             ALOGV("Removing built in display %d", displayType);
 
             ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
             if (idx >= 0) {
                 const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
-                mInterceptor.saveDisplayDeletion(info.displayId);
+                mInterceptor->saveDisplayDeletion(info.displayId);
                 mCurrentState.displays.removeItemsAt(idx);
             }
             mBuiltinDisplays[displayType].clear();
@@ -2142,6 +2200,84 @@
     mPendingHotplugEvents.clear();
 }
 
+sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
+        const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
+        const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
+    bool hasWideColorSupport = false;
+    if (hasWideColorDisplay) {
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(state.type);
+        for (ColorMode colorMode : modes) {
+            switch (colorMode) {
+                case ColorMode::DISPLAY_P3:
+                case ColorMode::ADOBE_RGB:
+                case ColorMode::DCI_P3:
+                    hasWideColorSupport = true;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    bool hasHdrSupport = false;
+    std::unique_ptr<HdrCapabilities> hdrCapabilities =
+            getHwComposer().getHdrCapabilities(state.type);
+    if (hdrCapabilities) {
+        const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
+        auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
+        hasHdrSupport = iter != types.cend();
+    }
+
+    auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
+    auto nativeWindow = nativeWindowSurface->getNativeWindow();
+
+    /*
+     * Create our display's surface
+     */
+    std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface();
+    renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
+    renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL);
+    renderSurface->setNativeWindow(nativeWindow.get());
+    const int displayWidth = renderSurface->queryWidth();
+    const int displayHeight = renderSurface->queryHeight();
+
+    // Make sure that composition can never be stalled by a virtual display
+    // consumer that isn't processing buffers fast enough. We have to do this
+    // in two places:
+    // * Here, in case the display is composed entirely by HWC.
+    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
+    //   window's swap interval in eglMakeCurrent, so they'll override the
+    //   interval we set here.
+    if (state.type >= DisplayDevice::DISPLAY_VIRTUAL) {
+        nativeWindow->setSwapInterval(nativeWindow.get(), 0);
+    }
+
+    // virtual displays are always considered enabled
+    auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL
+                                                                           : HWC_POWER_MODE_OFF;
+
+    sp<DisplayDevice> hw =
+            new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
+                              dispSurface, std::move(renderSurface), displayWidth, displayHeight,
+                              hasWideColorSupport, hasHdrSupport, initialPowerMode);
+
+    if (maxFrameBufferAcquiredBuffers >= 3) {
+        nativeWindowSurface->preallocateBuffers();
+    }
+
+    ColorMode defaultColorMode = ColorMode::NATIVE;
+    if (hasWideColorSupport) {
+        defaultColorMode = ColorMode::SRGB;
+    }
+    setActiveColorModeInternal(hw, defaultColorMode);
+    hw->setCompositionDataSpace(Dataspace::UNKNOWN);
+    hw->setLayerStack(state.layerStack);
+    hw->setProjection(state.orientation, state.viewport, state.frame);
+    hw->setDisplayName(state.displayName);
+
+    return hw;
+}
+
 void SurfaceFlinger::processDisplayChangesLocked() {
     // here we take advantage of Vector's copy-on-write semantics to
     // improve performance by skipping the transaction entirely when
@@ -2237,7 +2373,7 @@
                             int intFormat = 0;
                             status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat);
                             ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
-                            auto format = static_cast<android_pixel_format_t>(intFormat);
+                            auto format = static_cast<ui::PixelFormat>(intFormat);
 
                             getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
                         }
@@ -2264,50 +2400,10 @@
                 }
 
                 const wp<IBinder>& display(curr.keyAt(i));
-
                 if (dispSurface != nullptr) {
-                    bool hasWideColorSupport = false;
-                    if (hasWideColorDisplay) {
-                        std::vector<android_color_mode_t> modes =
-                                getHwComposer().getColorModes(state.type);
-                        for (android_color_mode_t colorMode : modes) {
-                            switch (colorMode) {
-                                case HAL_COLOR_MODE_DISPLAY_P3:
-                                case HAL_COLOR_MODE_ADOBE_RGB:
-                                case HAL_COLOR_MODE_DCI_P3:
-                                    hasWideColorSupport = true;
-                                    break;
-                                default:
-                                    break;
-                            }
-                        }
-                    }
-
-                    bool hasHdrSupport = false;
-                    std::unique_ptr<HdrCapabilities> hdrCapabilities =
-                        getHwComposer().getHdrCapabilities(state.type);
-                    if (hdrCapabilities) {
-                        const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
-                        auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
-                        hasHdrSupport = iter != types.cend();
-                    }
-
-                    sp<DisplayDevice> hw =
-                            new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
-                                              dispSurface, producer, hasWideColorSupport,
-                                              hasHdrSupport);
-
-                    android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
-                    if (hasWideColorSupport) {
-                        defaultColorMode = HAL_COLOR_MODE_SRGB;
-                    }
-                    setActiveColorModeInternal(hw, defaultColorMode);
-                    hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
-                    hw->setLayerStack(state.layerStack);
-                    hw->setProjection(state.orientation, state.viewport, state.frame);
-                    hw->setDisplayName(state.displayName);
-
-                    mDisplays.add(display, hw);
+                    mDisplays.add(display,
+                                  setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
+                                                                producer));
                     if (!state.isVirtualDisplay()) {
                         mEventThread->onHotplugReceived(state.type, true);
                     }
@@ -2738,10 +2834,10 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+        Dataspace outputDataspace = Dataspace::UNKNOWN;
         if (displayDevice->getWideColorSupport() &&
-                displayDevice->getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
-            outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+              displayDevice->getActiveColorMode() == ColorMode::DISPLAY_P3) {
+            outputDataspace = Dataspace::DISPLAY_P3;
         }
         getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
@@ -2895,8 +2991,11 @@
         }
 
         mGraphicBufferProducerList.insert(IInterface::asBinder(gbc).get());
-        LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > MAX_LAYERS,
-                            "Suspected IGBP leak");
+        // TODO (b/74616334): Change this back to a fatal assert once the leak is fixed
+        ALOGE_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize,
+                 "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+                 mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
+                 mNumLayers);
         mLayersAdded = true;
         mNumLayers++;
     }
@@ -3054,8 +3153,8 @@
     }
 
     if (transactionFlags) {
-        if (mInterceptor.isEnabled()) {
-            mInterceptor.saveTransaction(states, mCurrentState.displays, displays, flags);
+        if (mInterceptor->isEnabled()) {
+            mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
         }
 
         // this triggers the transaction
@@ -3309,7 +3408,7 @@
         const String8& name,
         const sp<Client>& client,
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-        uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
+        int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
         sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
 {
     if (int32_t(w|h) < 0) {
@@ -3358,7 +3457,7 @@
     if (result != NO_ERROR) {
         return result;
     }
-    mInterceptor.saveSurfaceCreation(layer);
+    mInterceptor->saveSurfaceCreation(layer);
 
     setTransactionFlags(eTransactionNeeded);
     return result;
@@ -3430,7 +3529,7 @@
     status_t err = NO_ERROR;
     sp<Layer> l(client->getLayerUser(handle));
     if (l != nullptr) {
-        mInterceptor.saveSurfaceDeletion(l);
+        mInterceptor->saveSurfaceDeletion(l);
         err = removeLayer(l);
         ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
                 "error removing layer=%p (%s)", l.get(), strerror(-err));
@@ -3512,14 +3611,14 @@
         return;
     }
 
-    if (mInterceptor.isEnabled()) {
+    if (mInterceptor->isEnabled()) {
         ConditionalLock lock(mStateLock, !stateLockHeld);
         ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
         if (idx < 0) {
             ALOGW("Surface Interceptor SavePowerMode: invalid display token");
             return;
         }
-        mInterceptor.savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
+        mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
     }
 
     if (currentMode == HWC_POWER_MODE_OFF) {
@@ -3581,6 +3680,7 @@
         ALOGE("Attempting to set unknown power mode: %d\n", mode);
         getHwComposer().setPowerMode(type, mode);
     }
+    ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType());
 }
 
 void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
@@ -3695,6 +3795,34 @@
                 dumpWideColorInfo(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--enable-layer-stats"))) {
+                index++;
+                mLayerStats.enable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--disable-layer-stats"))) {
+                index++;
+                mLayerStats.disable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--clear-layer-stats"))) {
+                index++;
+                mLayerStats.clear();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--dump-layer-stats"))) {
+                index++;
+                mLayerStats.dump(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -3878,12 +4006,12 @@
         }
 
         result.appendFormat("Display %d color modes:\n", hwcId);
-        std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(hwcId);
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
         for (auto&& mode : modes) {
             result.appendFormat("    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
         }
 
-        android_color_mode_t currentMode = displayDevice->getActiveColorMode();
+        ColorMode currentMode = displayDevice->getActiveColorMode();
         result.appendFormat("    Current color mode: %s (%d)\n",
                             decodeColorMode(currentMode).c_str(), currentMode);
     }
@@ -3902,6 +4030,29 @@
     return layersProto;
 }
 
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+    LayersProto layersProto;
+    const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+
+    SizeProto* resolution = layersProto.mutable_resolution();
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
+
+    layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
+    layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
+    layersProto.set_global_transform(
+            static_cast<int32_t>(displayDevice->getOrientationTransform()));
+
+    mDrawingState.traverseInZOrder([&](Layer* layer) {
+        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+            LayerProto* layerProto = layersProto.add_layers();
+            layer->writeToProto(layerProto, hwcId);
+        }
+    });
+
+    return layersProto;
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -3965,11 +4116,14 @@
      */
     colorizer.bold(result);
     result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
+    result.appendFormat("GraphicBufferProducers: %zu, max %zu\n",
+                        mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
     colorizer.reset(result);
 
     LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
     auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
-    result.append(LayerProtoParser::layersToString(layerTree).c_str());
+    result.append(LayerProtoParser::layersToString(std::move(layerTree)).c_str());
+    result.append("\n");
 
     /*
      * Dump Display state
@@ -3982,6 +4136,7 @@
         const sp<const DisplayDevice>& hw(mDisplays[dpy]);
         hw->dump(result);
     }
+    result.append("\n");
 
     /*
      * Dump SurfaceFlinger global state
@@ -4321,11 +4476,11 @@
                 n = data.readInt32();
                 if (n) {
                     ALOGV("Interceptor enabled");
-                    mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
+                    mInterceptor->enable(mDrawingState.layersSortedByZ, mDrawingState.displays);
                 }
                 else{
                     ALOGV("Interceptor disabled");
-                    mInterceptor.disable();
+                    mInterceptor->disable();
                 }
                 return NO_ERROR;
             }
@@ -4409,6 +4564,8 @@
     if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
 
     const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+    if (CC_UNLIKELY(device == 0)) return BAD_VALUE;
+
     DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
 
     auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
@@ -4418,19 +4575,18 @@
 
 status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
                                        sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
-                                       float frameScale) {
+                                       float frameScale, bool childrenOnly) {
     ATRACE_CALL();
 
     class LayerRenderArea : public RenderArea {
     public:
-        LayerRenderArea(const sp<Layer>& layer, const Rect crop, int32_t reqWidth,
-                        int32_t reqHeight)
-              : RenderArea(reqHeight, reqWidth), mLayer(layer), mCrop(crop) {}
-        const Transform& getTransform() const override {
-            // Make the top level transform the inverse the transform and it's parent so it sets
-            // the whole capture back to 0,0
-            return *new Transform(mLayer->getTransform().inverse());
-        }
+        LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
+                        int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
+              : RenderArea(reqHeight, reqWidth),
+                mLayer(layer),
+                mCrop(crop),
+                mFlinger(flinger),
+                mChildrenOnly(childrenOnly) {}
         Rect getBounds() const override {
             const Layer::State& layerState(mLayer->getDrawingState());
             return Rect(layerState.active.w, layerState.active.h);
@@ -4439,6 +4595,34 @@
         int getWidth() const override { return mLayer->getDrawingState().active.w; }
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return false; }
+        const Transform& getTransform() const { return mTransform; }
+
+        class ReparentForDrawing {
+        public:
+            const sp<Layer>& oldParent;
+            const sp<Layer>& newParent;
+
+            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+                  : oldParent(oldParent), newParent(newParent) {
+                oldParent->setChildrenDrawingParent(newParent);
+            }
+            ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+        };
+
+        void render(std::function<void()> drawLayers) override {
+            if (!mChildrenOnly) {
+                mTransform = mLayer->getTransform().inverse();
+                drawLayers();
+            } else {
+                Rect bounds = getBounds();
+                screenshotParentLayer =
+                        new ContainerLayer(mFlinger, nullptr, String8("Screenshot Parent"),
+                                           bounds.getWidth(), bounds.getHeight(), 0);
+
+                ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+                drawLayers();
+            }
+        }
 
         Rect getSourceCrop() const override {
             if (mCrop.isEmpty()) {
@@ -4448,11 +4632,19 @@
             }
         }
         bool getWideColorSupport() const override { return false; }
-        android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; }
+        ColorMode getActiveColorMode() const override { return ColorMode::NATIVE; }
 
     private:
         const sp<Layer> mLayer;
         const Rect mCrop;
+
+        // In the "childrenOnly" case we reparent the children to a screenshot
+        // layer which has no properties set and which does not draw.
+        sp<ContainerLayer> screenshotParentLayer;
+        Transform mTransform;
+
+        SurfaceFlinger* mFlinger;
+        const bool mChildrenOnly;
     };
 
     auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
@@ -4463,6 +4655,13 @@
         return NAME_NOT_FOUND;
     }
 
+    const int uid = IPCThreadState::self()->getCallingUid();
+    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+    if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+        ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
+        return PERMISSION_DENIED;
+    }
+
     Rect crop(sourceCrop);
     if (sourceCrop.width() <= 0) {
         crop.left = 0;
@@ -4477,12 +4676,14 @@
     int32_t reqWidth = crop.width() * frameScale;
     int32_t reqHeight = crop.height() * frameScale;
 
-    LayerRenderArea renderArea(parent, crop, reqWidth, reqHeight);
+    LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly);
 
-    auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
+    auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) {
         parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
             if (!layer->isVisible()) {
                 return;
+            } else if (childrenOnly && layer == parent.get()) {
+                return;
             }
             visitor(layer);
         });
@@ -4529,8 +4730,10 @@
         int fd = -1;
         {
             Mutex::Autolock _l(mStateLock);
-            result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
-                                             useIdentityTransform, forSystem, &fd);
+            renderArea.render([&]() {
+                result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+                                                 useIdentityTransform, forSystem, &fd);
+            });
         }
 
         {
@@ -4601,10 +4804,10 @@
         ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
-    android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+    Dataspace outputDataspace = Dataspace::UNKNOWN;
     if (renderArea.getWideColorSupport() &&
-            renderArea.getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
-        outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+          renderArea.getActiveColorMode() == ColorMode::DISPLAY_P3) {
+        outputDataspace = Dataspace::DISPLAY_P3;
     }
     getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 392acaa..23c9684 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -55,6 +55,7 @@
 #include "DisplayDevice.h"
 #include "DispSync.h"
 #include "FrameTracker.h"
+#include "LayerStats.h"
 #include "LayerVector.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
@@ -118,6 +119,19 @@
     eTransactionMask          = 0x07
 };
 
+// A thin interface to abstract creating instances of Surface (gui/Surface.h) to
+// use as a NativeWindow.
+class NativeWindowSurface {
+public:
+    virtual ~NativeWindowSurface();
+
+    // Gets the NativeWindow to use for the surface.
+    virtual sp<ANativeWindow> getNativeWindow() const = 0;
+
+    // Indicates that the surface should allocate its buffers now.
+    virtual void preallocateBuffers() = 0;
+};
+
 class SurfaceFlingerBE
 {
 public:
@@ -265,6 +279,9 @@
         return "SurfaceFlinger";
     }
 
+    struct SkipInitializationTag {};
+    static constexpr SkipInitializationTag SkipInitialization;
+    explicit SurfaceFlinger(SkipInitializationTag) ANDROID_API;
     SurfaceFlinger() ANDROID_API;
 
     // must be called before clients can connect
@@ -387,16 +404,16 @@
                                    int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
                                    ISurfaceComposer::Rotation rotation);
     virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
-                                   const Rect& sourceCrop, float frameScale);
+                                   const Rect& sourceCrop, float frameScale, bool childrenOnly);
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats);
     virtual status_t getDisplayConfigs(const sp<IBinder>& display,
             Vector<DisplayInfo>* configs);
     virtual int getActiveConfig(const sp<IBinder>& display);
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<android_color_mode_t>* configs);
-    virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display);
-    virtual status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode);
+            Vector<ui::ColorMode>* configs);
+    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
+    virtual status_t setActiveColorMode(const sp<IBinder>& display, ui::ColorMode colorMode);
     virtual void setPowerMode(const sp<IBinder>& display, int mode);
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
     virtual status_t clearAnimationFrameStats();
@@ -446,7 +463,7 @@
                               bool stateLockHeld);
 
     // Called on the main thread in response to setActiveColorMode()
-    void setActiveColorModeInternal(const sp<DisplayDevice>& hw, android_color_mode_t colorMode);
+    void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode);
 
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
@@ -485,7 +502,7 @@
      */
     status_t createLayer(const String8& name, const sp<Client>& client,
             uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
-            uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
+            int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
 
     status_t createBufferLayer(const sp<Client>& client, const String8& name,
@@ -619,8 +636,8 @@
 
     // Given a dataSpace, returns the appropriate color_mode to use
     // to display that dataSpace.
-    android_color_mode pickColorMode(android_dataspace dataSpace) const;
-    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b,
+    ui::ColorMode pickColorMode(ui::Dataspace dataSpace) const;
+    ui::Dataspace bestTargetDataSpace(ui::Dataspace a, ui::Dataspace b,
             bool hasHdr) const;
 
     mat4 computeSaturationMatrix() const;
@@ -629,6 +646,7 @@
     void doComposition();
     void doDebugFlashRegions();
     void doTracing(const char* where);
+    void logLayerStats();
     void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
 
     // compose surfaces for display hw. this fails if using GL and the surface
@@ -643,6 +661,10 @@
      */
     DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
             HWC2::Connection connection) const;
+    sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+                                                    const DisplayDeviceState& state,
+                                                    const sp<DisplaySurface>& dispSurface,
+                                                    const sp<IGraphicBufferProducer>& producer);
     void processDisplayChangesLocked();
     void processDisplayHotplugEventsLocked();
 
@@ -691,6 +713,7 @@
     void dumpBufferingStats(String8& result) const;
     void dumpWideColorInfo(String8& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+    LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -720,6 +743,7 @@
 
     // Can't be unordered_set because wp<> isn't hashable
     std::set<wp<IBinder>> mGraphicBufferProducerList;
+    size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
 
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved;
@@ -773,15 +797,17 @@
     bool mBootFinished;
     bool mForceFullDamage;
     bool mPropagateBackpressure = true;
-    SurfaceInterceptor mInterceptor;
+    std::unique_ptr<SurfaceInterceptor> mInterceptor =
+            std::make_unique<impl::SurfaceInterceptor>(this);
     SurfaceTracing mTracing;
+    LayerStats mLayerStats;
     bool mUseHwcVirtualDisplays = false;
 
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
 
     // these are thread safe
-    mutable MessageQueue mEventQueue;
+    mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
     FrameTracker mAnimFrameTracker;
     DispSync mPrimaryDispSync;
 
@@ -832,6 +858,10 @@
                                bool /* consumerIsSurfaceFlinger */)>;
     CreateBufferQueueFunction mCreateBufferQueue;
 
+    using CreateNativeWindowSurfaceFunction =
+            std::function<std::unique_ptr<NativeWindowSurface>(const sp<IGraphicBufferProducer>&)>;
+    CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+
     SurfaceFlingerBE mBE;
 };
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index eeb4929..4596a21 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -31,6 +31,10 @@
 
 // ----------------------------------------------------------------------------
 
+SurfaceInterceptor::~SurfaceInterceptor() = default;
+
+namespace impl {
+
 SurfaceInterceptor::SurfaceInterceptor(SurfaceFlinger* flinger)
     :   mFlinger(flinger)
 {
@@ -593,5 +597,5 @@
     addPowerModeUpdateLocked(createTraceIncrementLocked(), displayId, mode);
 }
 
-
+} // namespace impl
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 30ebcc6..96defcc 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -21,48 +21,89 @@
 
 #include <mutex>
 
+#include <gui/LayerState.h>
+
+#include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
+#include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
+#include "DisplayDevice.h"
+
 namespace android {
 
 class BufferItem;
 class Layer;
 class SurfaceFlinger;
+struct ComposerState;
+struct DisplayDeviceState;
 struct DisplayState;
 struct layer_state_t;
 
 constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
 
+class SurfaceInterceptor {
+public:
+    virtual ~SurfaceInterceptor();
+
+    // Both vectors are used to capture the current state of SF as the initial snapshot in the trace
+    virtual void enable(const SortedVector<sp<Layer>>& layers,
+                        const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) = 0;
+    virtual void disable() = 0;
+    virtual bool isEnabled() = 0;
+
+    // Intercept display and surface transactions
+    virtual void saveTransaction(
+            const Vector<ComposerState>& stateUpdates,
+            const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+            const Vector<DisplayState>& changedDisplays, uint32_t flags) = 0;
+
+    // Intercept surface data
+    virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
+    virtual void saveSurfaceDeletion(const sp<const Layer>& layer) = 0;
+    virtual void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+                                  uint64_t frameNumber) = 0;
+
+    // Intercept display data
+    virtual void saveDisplayCreation(const DisplayDeviceState& info) = 0;
+    virtual void saveDisplayDeletion(int32_t displayId) = 0;
+    virtual void savePowerModeUpdate(int32_t displayId, int32_t mode) = 0;
+    virtual void saveVSyncEvent(nsecs_t timestamp) = 0;
+};
+
+namespace impl {
+
 /*
  * SurfaceInterceptor intercepts and stores incoming streams of window
  * properties on SurfaceFlinger.
  */
-class SurfaceInterceptor {
+class SurfaceInterceptor final : public android::SurfaceInterceptor {
 public:
-    SurfaceInterceptor(SurfaceFlinger* const flinger);
+    explicit SurfaceInterceptor(SurfaceFlinger* const flinger);
+    ~SurfaceInterceptor() override = default;
+
     // Both vectors are used to capture the current state of SF as the initial snapshot in the trace
     void enable(const SortedVector<sp<Layer>>& layers,
-            const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays);
-    void disable();
-    bool isEnabled();
+                const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays) override;
+    void disable() override;
+    bool isEnabled() override;
 
     // Intercept display and surface transactions
     void saveTransaction(const Vector<ComposerState>& stateUpdates,
-            const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays,
-            const Vector<DisplayState>& changedDisplays, uint32_t flags);
+                         const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
+                         const Vector<DisplayState>& changedDisplays, uint32_t flags) override;
 
     // Intercept surface data
-    void saveSurfaceCreation(const sp<const Layer>& layer);
-    void saveSurfaceDeletion(const sp<const Layer>& layer);
+    void saveSurfaceCreation(const sp<const Layer>& layer) override;
+    void saveSurfaceDeletion(const sp<const Layer>& layer) override;
     void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
-            uint64_t frameNumber);
+                          uint64_t frameNumber) override;
 
     // Intercept display data
-    void saveDisplayCreation(const DisplayDeviceState& info);
-    void saveDisplayDeletion(int32_t displayId);
-    void savePowerModeUpdate(int32_t displayId, int32_t mode);
-    void saveVSyncEvent(nsecs_t timestamp);
+    void saveDisplayCreation(const DisplayDeviceState& info) override;
+    void saveDisplayDeletion(int32_t displayId) override;
+    void savePowerModeUpdate(int32_t displayId, int32_t mode) override;
+    void saveVSyncEvent(nsecs_t timestamp) override;
 
 private:
     // The creation increments of Surfaces and Displays do not contain enough information to capture
@@ -134,6 +175,7 @@
     SurfaceFlinger* const mFlinger;
 };
 
-}
+} // namespace impl
+} // namespace android
 
 #endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index 485090c..ac147fe 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -10,6 +10,7 @@
     ],
 
     shared_libs: [
+        "android.hardware.graphics.common@1.1",
         "libui",
         "libprotobuf-cpp-lite",
         "libbase",
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index bf37e1e..fcf42f0 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include <android-base/stringprintf.h>
 #include <layerproto/LayerProtoParser.h>
 #include <ui/DebugUtils.h>
@@ -24,7 +23,7 @@
 namespace android {
 namespace surfaceflinger {
 
-bool sortLayers(const LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
+bool sortLayers(LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
     uint32_t ls = lhs->layerStack;
     uint32_t rs = rhs->layerStack;
     if (ls != rs) return ls < rs;
@@ -38,20 +37,35 @@
     return lhs->id < rhs->id;
 }
 
-std::vector<const LayerProtoParser::Layer*> LayerProtoParser::generateLayerTree(
+bool sortLayerUniquePtrs(const std::unique_ptr<LayerProtoParser::Layer>& lhs,
+                   const std::unique_ptr<LayerProtoParser::Layer>& rhs) {
+    return sortLayers(lhs.get(), rhs.get());
+}
+
+const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
         const LayersProto& layersProto) {
-    auto layerMap = generateMap(layersProto);
+    LayerGlobal layerGlobal;
+    layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
+    layerGlobal.colorMode = layersProto.color_mode();
+    layerGlobal.colorTransform = layersProto.color_transform();
+    layerGlobal.globalTransform = layersProto.global_transform();
+    return layerGlobal;
+}
 
-    std::vector<const Layer*> layers;
-    std::for_each(layerMap.begin(), layerMap.end(),
-                  [&](const std::pair<const int32_t, Layer*>& ref) {
-                      if (ref.second->parent == nullptr) {
-                          // only save top level layers
-                          layers.push_back(ref.second);
-                      }
-                  });
+std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree(
+        const LayersProto& layersProto) {
+    std::unordered_map<int32_t, LayerProtoParser::Layer*> layerMap = generateMap(layersProto);
+    std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers;
 
-    std::sort(layers.begin(), layers.end(), sortLayers);
+    for (std::pair<int32_t, Layer*> kv : layerMap) {
+        if (kv.second->parent == nullptr) {
+            // Make unique_ptr for top level layers since they are not children. This ensures there
+            // will only be one unique_ptr made for each layer.
+            layers.push_back(std::unique_ptr<Layer>(kv.second));
+        }
+    }
+
+    std::sort(layers.begin(), layers.end(), sortLayerUniquePtrs);
     return layers;
 }
 
@@ -102,6 +116,13 @@
     layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
     layer->queuedFrames = layerProto.queued_frames();
     layer->refreshPending = layerProto.refresh_pending();
+    layer->hwcFrame = generateRect(layerProto.hwc_frame());
+    layer->hwcCrop = generateFloatRect(layerProto.hwc_crop());
+    layer->hwcTransform = layerProto.hwc_transform();
+    layer->windowType = layerProto.window_type();
+    layer->appId = layerProto.app_id();
+    layer->hwcCompositionType = layerProto.hwc_composition_type();
+    layer->isProtected = layerProto.is_protected();
 
     return layer;
 }
@@ -127,6 +148,16 @@
     return rect;
 }
 
+LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) {
+    LayerProtoParser::FloatRect rect;
+    rect.left = rectProto.left();
+    rect.top = rectProto.top();
+    rect.right = rectProto.right();
+    rect.bottom = rectProto.bottom();
+
+    return rect;
+}
+
 LayerProtoParser::Transform LayerProtoParser::generateTransform(
         const TransformProto& transformProto) {
     LayerProtoParser::Transform transform;
@@ -155,63 +186,61 @@
 
     for (int i = 0; i < layerProto.children_size(); i++) {
         if (layerMap.count(layerProto.children(i)) > 0) {
-            auto childLayer = layerMap[layerProto.children(i)];
-            currLayer->children.push_back(childLayer);
+            // Only make unique_ptrs for children since they are guaranteed to be unique, only one
+            // parent per child. This ensures there will only be one unique_ptr made for each layer.
+            currLayer->children.push_back(std::unique_ptr<Layer>(layerMap[layerProto.children(i)]));
         }
     }
 
     for (int i = 0; i < layerProto.relatives_size(); i++) {
         if (layerMap.count(layerProto.relatives(i)) > 0) {
-            auto relativeLayer = layerMap[layerProto.relatives(i)];
-            currLayer->relatives.push_back(relativeLayer);
+            currLayer->relatives.push_back(layerMap[layerProto.relatives(i)]);
         }
     }
 
     if (layerProto.has_parent()) {
         if (layerMap.count(layerProto.parent()) > 0) {
-            auto parentLayer = layerMap[layerProto.parent()];
-            currLayer->parent = parentLayer;
+            currLayer->parent = layerMap[layerProto.parent()];
         }
     }
 
     if (layerProto.has_z_order_relative_of()) {
         if (layerMap.count(layerProto.z_order_relative_of()) > 0) {
-            auto relativeLayer = layerMap[layerProto.z_order_relative_of()];
-            currLayer->zOrderRelativeOf = relativeLayer;
+            currLayer->zOrderRelativeOf = layerMap[layerProto.z_order_relative_of()];
         }
     }
 }
 
 std::string LayerProtoParser::layersToString(
-        const std::vector<const LayerProtoParser::Layer*> layers) {
+        std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers) {
     std::string result;
-    for (const LayerProtoParser::Layer* layer : layers) {
+    for (std::unique_ptr<LayerProtoParser::Layer>& layer : layers) {
         if (layer->zOrderRelativeOf != nullptr) {
             continue;
         }
-        result.append(layerToString(layer).c_str());
+        result.append(layerToString(layer.get()).c_str());
     }
 
     return result;
 }
 
-std::string LayerProtoParser::layerToString(const LayerProtoParser::Layer* layer) {
+std::string LayerProtoParser::layerToString(LayerProtoParser::Layer* layer) {
     std::string result;
 
-    std::vector<const Layer*> traverse(layer->relatives);
-    for (const LayerProtoParser::Layer* child : layer->children) {
+    std::vector<Layer*> traverse(layer->relatives);
+    for (std::unique_ptr<LayerProtoParser::Layer>& child : layer->children) {
         if (child->zOrderRelativeOf != nullptr) {
             continue;
         }
 
-        traverse.push_back(child);
+        traverse.push_back(child.get());
     }
 
     std::sort(traverse.begin(), traverse.end(), sortLayers);
 
     size_t i = 0;
     for (; i < traverse.size(); i++) {
-        const auto& relative = traverse[i];
+        auto& relative = traverse[i];
         if (relative->z >= 0) {
             break;
         }
@@ -220,7 +249,7 @@
     result.append(layer->to_string().c_str());
     result.append("\n");
     for (; i < traverse.size(); i++) {
-        const auto& relative = traverse[i];
+        auto& relative = traverse[i];
         result.append(layerToString(relative).c_str());
     }
 
@@ -242,6 +271,10 @@
     return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
 }
 
+std::string LayerProtoParser::FloatRect::to_string() const {
+    return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom);
+}
+
 std::string LayerProtoParser::Region::to_string(const char* what) const {
     std::string result =
             StringPrintf("  Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
@@ -269,7 +302,7 @@
                   finalCrop.to_string().c_str());
     StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", isOpaque, invalidate);
     StringAppendF(&result, "dataspace=%s, ", dataspace.c_str());
-    StringAppendF(&result, "pixelformat=%s, ", pixelFormat.c_str());
+    StringAppendF(&result, "defaultPixelFormat=%s, ", pixelFormat.c_str());
     StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
                   static_cast<double>(color.r), static_cast<double>(color.g),
                   static_cast<double>(color.b), static_cast<double>(color.a), flags);
@@ -279,7 +312,8 @@
     StringAppendF(&result, "      zOrderRelativeOf=%s\n",
                   zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
     StringAppendF(&result, "      activeBuffer=%s,", activeBuffer.to_string().c_str());
-    StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", queuedFrames, refreshPending);
+    StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
+    StringAppendF(&result, " windowType=%d, appId=%d", windowType, appId);
 
     return result;
 }
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 78c6cd1..74a6f28 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <layerproto/LayerProtoHeader.h>
 
 #include <math/vec4.h>
 
+#include <memory>
 #include <unordered_map>
 #include <vector>
 
@@ -56,6 +58,16 @@
         std::string to_string() const;
     };
 
+    class FloatRect {
+    public:
+        float left;
+        float top;
+        float right;
+        float bottom;
+
+        std::string to_string() const;
+    };
+
     class Region {
     public:
         uint64_t id;
@@ -68,8 +80,8 @@
     public:
         int32_t id;
         std::string name;
-        std::vector<const Layer*> children;
-        std::vector<const Layer*> relatives;
+        std::vector<std::unique_ptr<Layer>> children;
+        std::vector<Layer*> relatives;
         std::string type;
         LayerProtoParser::Region transparentRegion;
         LayerProtoParser::Region visibleRegion;
@@ -95,25 +107,42 @@
         LayerProtoParser::ActiveBuffer activeBuffer;
         int32_t queuedFrames;
         bool refreshPending;
+        LayerProtoParser::Rect hwcFrame;
+        LayerProtoParser::FloatRect hwcCrop;
+        int32_t hwcTransform;
+        int32_t windowType;
+        int32_t appId;
+        int32_t hwcCompositionType;
+        bool isProtected;
 
         std::string to_string() const;
     };
 
-    static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto);
-    static std::string layersToString(const std::vector<const LayerProtoParser::Layer*> layers);
+    class LayerGlobal {
+    public:
+        int2 resolution;
+        std::string colorMode;
+        std::string colorTransform;
+        int32_t globalTransform;
+    };
+
+    static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
+    static std::vector<std::unique_ptr<Layer>> generateLayerTree(const LayersProto& layersProto);
+    static std::string layersToString(std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers);
 
 private:
     static std::unordered_map<int32_t, Layer*> generateMap(const LayersProto& layersProto);
     static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
     static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
     static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+    static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto);
     static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
     static LayerProtoParser::ActiveBuffer generateActiveBuffer(
             const ActiveBufferProto& activeBufferProto);
     static void updateChildrenAndRelative(const LayerProto& layerProto,
                                           std::unordered_map<int32_t, Layer*>& layerMap);
 
-    static std::string layerToString(const LayerProtoParser::Layer* layer);
+    static std::string layerToString(LayerProtoParser::Layer* layer);
 };
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index d27dc9b..77c6675 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,6 +7,10 @@
 // Contains a list of all layers.
 message LayersProto {
   repeated LayerProto layers = 1;
+  optional SizeProto resolution = 2;
+  optional string color_mode = 3;
+  optional string color_transform = 4;
+  optional int32 global_transform = 5;
 }
 
 // Information about each layer.
@@ -64,6 +68,18 @@
   // The number of frames available.
   optional int32 queued_frames = 28;
   optional bool refresh_pending = 29;
+  // The layer's composer backend destination frame
+  optional RectProto hwc_frame = 30;
+  // The layer's composer backend source crop
+  optional FloatRectProto hwc_crop = 31;
+  // The layer's composer backend transform
+  optional int32 hwc_transform = 32;
+  optional int32 window_type = 33;
+  optional int32 app_id = 34;
+  // The layer's composition type
+  optional int32 hwc_composition_type = 35;
+  // If it's a buffer layer, indicate if the content is protected
+  optional bool is_protected = 36;
 }
 
 message PositionProto {
@@ -95,6 +111,13 @@
   optional int32 bottom = 4;
 }
 
+message FloatRectProto {
+  optional float left = 1;
+  optional float top = 2;
+  optional float right = 3;
+  optional float bottom = 4;
+}
+
 message ActiveBufferProto {
   optional uint32 width = 1;
   optional uint32 height = 2;
@@ -107,4 +130,4 @@
   optional float g = 2;
   optional float b = 3;
   optional float a = 4;
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 7d3da32..7523399 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -33,6 +33,7 @@
         "libEGL",
         "libGLESv2",
         "libgui",
+        "liblayers_proto",
         "liblog",
         "libprotobuf-cpp-full",
         "libui",
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 33dd2f5..4577153 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -22,7 +22,7 @@
 
 #include <thread>
 #include <functional>
-
+#include <layerproto/LayerProtoParser.h>
 
 namespace android {
 
@@ -47,4 +47,66 @@
     }
 }
 
+surfaceflinger::LayersProto generateLayerProto() {
+    surfaceflinger::LayersProto layersProto;
+    std::array<surfaceflinger::LayerProto*, 10> layers = {};
+    for (size_t i = 0; i < layers.size(); ++i) {
+        layers[i] = layersProto.add_layers();
+        layers[i]->set_id(i);
+    }
+
+    layers[0]->add_children(1);
+    layers[1]->set_parent(0);
+    layers[0]->add_children(2);
+    layers[2]->set_parent(0);
+    layers[0]->add_children(3);
+    layers[3]->set_parent(0);
+    layers[2]->add_children(4);
+    layers[4]->set_parent(2);
+    layers[3]->add_children(5);
+    layers[5]->set_parent(3);
+    layers[5]->add_children(6);
+    layers[6]->set_parent(5);
+    layers[5]->add_children(7);
+    layers[7]->set_parent(5);
+    layers[6]->add_children(8);
+    layers[8]->set_parent(6);
+
+    layers[4]->set_z_order_relative_of(3);
+    layers[3]->add_relatives(4);
+    layers[8]->set_z_order_relative_of(9);
+    layers[9]->add_relatives(8);
+    layers[3]->set_z_order_relative_of(1);
+    layers[1]->add_relatives(3);
+
+/* ----------------------------
+ *       - 0 -      - 9 -
+ *      /  |  \
+ *     1   2   3(1)
+ *         |    |
+ *         4(3) 5
+ *             / \
+ *            6   7
+ *            |
+ *            8(9)
+ * -------------------------- */
+
+    return layersProto;
+}
+
+TEST(LayerProtoStress, mem_info) {
+    std::string cmd = "dumpsys meminfo ";
+    cmd += std::to_string(getpid());
+    system(cmd.c_str());
+    for (int i = 0; i < 100000; i++) {
+        surfaceflinger::LayersProto layersProto = generateLayerProto();
+        auto layerTree = surfaceflinger::LayerProtoParser::generateLayerTree(layersProto);
+        // Allow some layerTrees to just fall out of scope (instead of std::move)
+        if (i % 2) {
+            surfaceflinger::LayerProtoParser::layersToString(std::move(layerTree));
+        }
+    }
+    system(cmd.c_str());
+}
+
 }
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 92c26af..4e9db72 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -192,6 +192,16 @@
         *sc = std::make_unique<ScreenCapture>(outBuffer);
     }
 
+    static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+                                   Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
         expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
@@ -2306,6 +2316,85 @@
     mCapture->expectChildColor(0, 0);
 }
 
+TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                                           0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    // Captures mFGSurfaceControl's child
+    ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->expectChildColor(0, 0);
+}
+
+
+// In the following tests we verify successful skipping of a parent layer,
+// so we use the same verification logic and only change how we mutate
+// the parent layer to verify that various properties are ignored.
+class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
+public:
+    void SetUp() override {
+        LayerUpdateTest::SetUp();
+
+        mChild =
+            mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+                    0, mFGSurfaceControl.get());
+        fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+        SurfaceComposerClient::Transaction().show(mChild).apply(true);
+    }
+
+    void verify() {
+        auto fgHandle = mFGSurfaceControl->getHandle();
+        ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+        mCapture->checkPixel(10, 10, 0, 0, 0);
+        mCapture->expectChildColor(0, 0);
+    }
+
+    std::unique_ptr<ScreenCapture> mCapture;
+    sp<SurfaceControl> mChild;
+};
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
+
+    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+    // Even though the parent is hidden we should still capture the child.
+    verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
+
+    SurfaceComposerClient::Transaction().setCrop(mFGSurfaceControl, Rect(0, 0, 1, 1)).apply(true);
+
+    // Even though the parent is cropped out we should still capture the child.
+    verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
+
+    SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2);
+
+    // We should not inherit the parent scaling.
+    verify();
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, RegressionTest76099859) {
+    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+    // Even though the parent is hidden we should still capture the child.
+    verify();
+
+    // Verify everything was properly hidden when rendering the full-screen.
+    screenshot()->expectBGColor(0,0);
+}
+
+
 TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
     auto fgHandle = mFGSurfaceControl->getHandle();
 
diff --git a/services/surfaceflinger/tests/hwc2/Android.bp b/services/surfaceflinger/tests/hwc2/Android.bp
index e980522..6c0e4ab 100644
--- a/services/surfaceflinger/tests/hwc2/Android.bp
+++ b/services/surfaceflinger/tests/hwc2/Android.bp
@@ -42,6 +42,7 @@
     ],
     shared_libs: [
         "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
         "libcutils",
         "libEGL",
         "libGLESv2",
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 4878c14..13774b4 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -22,6 +22,7 @@
 #include <android-base/unique_fd.h>
 #include <hardware/hardware.h>
 #include <sync/sync.h>
+#include <ui/GraphicTypes.h>
 
 #define HWC2_INCLUDE_STRINGIFICATION
 #define HWC2_USE_CPP11
@@ -34,6 +35,9 @@
 #include "Hwc2TestClientTarget.h"
 #include "Hwc2TestVirtualDisplay.h"
 
+using android::ui::ColorMode;
+using android::ui::Dataspace;
+
 void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
         hwc2_display_t display, int32_t connected);
 void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
@@ -439,14 +443,14 @@
     }
 
     void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer,
-            android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr)
+            Dataspace dataspace, hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>(
                 getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE));
         ASSERT_TRUE(pfn) << "failed to get function";
 
         auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                layer, dataspace));
+                layer, static_cast<int>(dataspace)));
         if (outErr) {
             *outErr = err;
         } else {
@@ -787,14 +791,14 @@
 
     void getClientTargetSupport(hwc2_display_t display, int32_t width,
             int32_t height, android_pixel_format_t format,
-            android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr)
+            Dataspace dataspace, hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
                 getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT));
         ASSERT_TRUE(pfn) << "failed to get function";
 
         auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width,
-                height, format, dataspace));
+                height, format, static_cast<int>(dataspace)));
         if (outErr) {
             *outErr = err;
         } else {
@@ -804,7 +808,7 @@
     }
 
     void setClientTarget(hwc2_display_t display, buffer_handle_t handle,
-            int32_t acquireFence, android_dataspace_t dataspace,
+            int32_t acquireFence, Dataspace dataspace,
             hwc_region_t damage, hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>(
@@ -812,7 +816,7 @@
         ASSERT_TRUE(pfn) << "failed to get function";
 
         auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle,
-                acquireFence, dataspace, damage));
+                acquireFence, static_cast<int>(dataspace), damage));
         if (outErr) {
             *outErr = err;
         } else {
@@ -865,7 +869,7 @@
     }
 
     void getColorModes(hwc2_display_t display,
-            std::vector<android_color_mode_t>* outColorModes,
+            std::vector<ColorMode>* outColorModes,
             hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_GET_COLOR_MODES>(
@@ -892,7 +896,7 @@
         }
     }
 
-    void setColorMode(hwc2_display_t display, android_color_mode_t colorMode,
+    void setColorMode(hwc2_display_t display, ColorMode colorMode,
             hwc2_error_t* outErr = nullptr)
     {
         auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_MODE>(
@@ -905,7 +909,7 @@
             *outErr = err;
         } else {
             ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color mode "
-                    << colorMode;
+                    << static_cast<int>(colorMode);
         }
     }
 
@@ -1688,7 +1692,7 @@
             const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
             const Area& displayArea)
     {
-        android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+        Dataspace dataspace = Dataspace::UNKNOWN;
         hwc_region_t damage = { };
         buffer_handle_t handle;
         int32_t acquireFence;
@@ -3713,7 +3717,7 @@
  * layer. */
 TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic)
 {
-    const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+    const Dataspace dataspace = Dataspace::UNKNOWN;
     const hwc_region_t damage = { };
     const size_t layerCnt = 1;
 
@@ -3792,7 +3796,7 @@
     std::set<hwc2_layer_t> clientLayers;
     std::set<hwc2_layer_t> flipClientTargetLayers;
     bool flipClientTarget = true;
-    const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+    const Dataspace dataspace = Dataspace::UNKNOWN;
     const hwc_region_t damage = { };
     buffer_handle_t handle;
     int32_t acquireFence;
@@ -4252,33 +4256,33 @@
     EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
 }
 
-static const std::array<android_color_mode, 9> androidColorModes = {{
-    HAL_COLOR_MODE_NATIVE,
-    HAL_COLOR_MODE_STANDARD_BT601_625,
-    HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED,
-    HAL_COLOR_MODE_STANDARD_BT601_525,
-    HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED,
-    HAL_COLOR_MODE_STANDARD_BT709,
-    HAL_COLOR_MODE_DCI_P3,
-    HAL_COLOR_MODE_SRGB,
-    HAL_COLOR_MODE_ADOBE_RGB,
+static const std::array<ColorMode, 9> androidColorModes = {{
+    ColorMode::NATIVE,
+    ColorMode::STANDARD_BT601_625,
+    ColorMode::STANDARD_BT601_625_UNADJUSTED,
+    ColorMode::STANDARD_BT601_525,
+    ColorMode::STANDARD_BT601_525_UNADJUSTED,
+    ColorMode::STANDARD_BT709,
+    ColorMode::DCI_P3,
+    ColorMode::SRGB,
+    ColorMode::ADOBE_RGB,
 }};
 
 /* TESTCASE: Tests that the HWC2 can get the color modes for a display. The
- * display must support HAL_COLOR_MODE_NATIVE */
+ * display must support ColorMode::NATIVE */
 TEST_F(Hwc2Test, GET_COLOR_MODES)
 {
     ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
             [] (Hwc2Test* test, hwc2_display_t display) {
 
-                std::vector<android_color_mode_t> colorModes;
+                std::vector<ColorMode> colorModes;
 
                 ASSERT_NO_FATAL_FAILURE(test->getColorModes(display,
                         &colorModes));
 
                 EXPECT_NE(std::count(colorModes.begin(), colorModes.end(),
-                        HAL_COLOR_MODE_NATIVE), 0) << "all displays"
-                        " must support HAL_COLOR_MODE_NATIVE";
+                        ColorMode::NATIVE), 0) << "all displays"
+                        " must support ColorMode::NATIVE";
             }
     ));
 }
@@ -4287,7 +4291,7 @@
 TEST_F(Hwc2Test, GET_COLOR_MODES_bad_display)
 {
     hwc2_display_t display;
-    std::vector<android_color_mode_t> colorModes;
+    std::vector<ColorMode> colorModes;
     hwc2_error_t err = HWC2_ERROR_NONE;
 
     ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
@@ -4302,7 +4306,7 @@
     ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
             [] (Hwc2Test* test, hwc2_display_t display) {
 
-                const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE;
+                const ColorMode colorMode = ColorMode::NATIVE;
 
                 EXPECT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode));
             }
@@ -4313,7 +4317,7 @@
 TEST_F(Hwc2Test, SET_COLOR_MODES_bad_display)
 {
     hwc2_display_t display;
-    const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE;
+    const ColorMode colorMode = ColorMode::NATIVE;
     hwc2_error_t err = HWC2_ERROR_NONE;
 
     ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
@@ -4328,8 +4332,7 @@
     ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
             [] (Hwc2Test* test, hwc2_display_t display) {
 
-                const android_color_mode_t colorMode =
-                        static_cast<android_color_mode_t>(-1);
+                const ColorMode colorMode = static_cast<ColorMode>(-1);
                 hwc2_error_t err = HWC2_ERROR_NONE;
 
                 ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode,
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
index 6925492..14c60a7 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
@@ -91,7 +91,7 @@
     return mBufferArea.get();
 }
 
-android_dataspace_t Hwc2TestClientTargetSupport::getDataspace() const
+android::ui::Dataspace Hwc2TestClientTargetSupport::getDataspace() const
 {
     return mDataspace.get();
 }
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
index 3b47978..6f4090f 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
@@ -53,7 +53,7 @@
     bool advance();
 
     Area getBufferArea() const;
-    android_dataspace_t getDataspace() const;
+    android::ui::Dataspace getDataspace() const;
     const hwc_region_t getSurfaceDamage() const;
 
 private:
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
index 937fce2..c1c9cc8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
@@ -146,7 +146,7 @@
     return mDisplayFrame.get();
 }
 
-android_dataspace_t Hwc2TestLayer::getDataspace() const
+android::ui::Dataspace Hwc2TestLayer::getDataspace() const
 {
     return mDataspace.get();
 }
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
index 0e7dd22..29ae521 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
@@ -54,7 +54,7 @@
     hwc_color_t            getColor() const;
     hwc2_composition_t     getComposition() const;
     hwc_rect_t             getCursorPosition() const;
-    android_dataspace_t    getDataspace() const;
+    android::ui::Dataspace     getDataspace() const;
     hwc_rect_t             getDisplayFrame() const;
     float                  getPlaneAlpha() const;
     hwc_frect_t            getSourceCrop() const;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
index 495ef79..90127a1 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
@@ -169,7 +169,7 @@
     return mTestLayers.at(layer).getCursorPosition();
 }
 
-android_dataspace_t Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
+android::ui::Dataspace Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
 {
     if (mTestLayers.count(layer) == 0) {
         []() { GTEST_FAIL(); }();
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
index d95a91f..909dd48 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
@@ -63,7 +63,7 @@
     hwc_color_t            getColor(hwc2_layer_t layer) const;
     hwc2_composition_t     getComposition(hwc2_layer_t layer) const;
     hwc_rect_t             getCursorPosition(hwc2_layer_t layer) const;
-    android_dataspace_t    getDataspace(hwc2_layer_t layer) const;
+    android::ui::Dataspace     getDataspace(hwc2_layer_t layer) const;
     hwc_rect_t             getDisplayFrame(hwc2_layer_t layer) const;
     android_pixel_format_t getFormat(hwc2_layer_t layer) const;
     float                  getPlaneAlpha(hwc2_layer_t layer) const;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
index 5b3bbeb..c5b92d0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -262,62 +262,62 @@
 std::string Hwc2TestDataspace::dump() const
 {
     std::stringstream dmp;
-    dmp << "\tdataspace: " << get() << "\n";
+    dmp << "\tdataspace: " << static_cast<int32_t>(get()) << "\n";
     return dmp.str();
 }
 
-const std::vector<android_dataspace_t> Hwc2TestDataspace::defaultDataspaces = {
-    HAL_DATASPACE_UNKNOWN,
+const std::vector<android::ui::Dataspace> Hwc2TestDataspace::defaultDataspaces = {
+    android::ui::Dataspace::UNKNOWN,
 };
 
-const std::vector<android_dataspace_t> Hwc2TestDataspace::basicDataspaces = {
-    HAL_DATASPACE_UNKNOWN,
-    HAL_DATASPACE_V0_SRGB,
+const std::vector<android::ui::Dataspace> Hwc2TestDataspace::basicDataspaces = {
+    android::ui::Dataspace::UNKNOWN,
+    android::ui::Dataspace::V0_SRGB,
 };
 
-const std::vector<android_dataspace_t> Hwc2TestDataspace::completeDataspaces = {
-    HAL_DATASPACE_UNKNOWN,
-    HAL_DATASPACE_ARBITRARY,
-    HAL_DATASPACE_STANDARD_SHIFT,
-    HAL_DATASPACE_STANDARD_MASK,
-    HAL_DATASPACE_STANDARD_UNSPECIFIED,
-    HAL_DATASPACE_STANDARD_BT709,
-    HAL_DATASPACE_STANDARD_BT601_625,
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED,
-    HAL_DATASPACE_STANDARD_BT601_525,
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED,
-    HAL_DATASPACE_STANDARD_BT2020,
-    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE,
-    HAL_DATASPACE_STANDARD_BT470M,
-    HAL_DATASPACE_STANDARD_FILM,
-    HAL_DATASPACE_TRANSFER_SHIFT,
-    HAL_DATASPACE_TRANSFER_MASK,
-    HAL_DATASPACE_TRANSFER_UNSPECIFIED,
-    HAL_DATASPACE_TRANSFER_LINEAR,
-    HAL_DATASPACE_TRANSFER_SRGB,
-    HAL_DATASPACE_TRANSFER_SMPTE_170M,
-    HAL_DATASPACE_TRANSFER_GAMMA2_2,
-    HAL_DATASPACE_TRANSFER_GAMMA2_8,
-    HAL_DATASPACE_TRANSFER_ST2084,
-    HAL_DATASPACE_TRANSFER_HLG,
-    HAL_DATASPACE_RANGE_SHIFT,
-    HAL_DATASPACE_RANGE_MASK,
-    HAL_DATASPACE_RANGE_UNSPECIFIED,
-    HAL_DATASPACE_RANGE_FULL,
-    HAL_DATASPACE_RANGE_LIMITED,
-    HAL_DATASPACE_SRGB_LINEAR,
-    HAL_DATASPACE_V0_SRGB_LINEAR,
-    HAL_DATASPACE_SRGB,
-    HAL_DATASPACE_V0_SRGB,
-    HAL_DATASPACE_JFIF,
-    HAL_DATASPACE_V0_JFIF,
-    HAL_DATASPACE_BT601_625,
-    HAL_DATASPACE_V0_BT601_625,
-    HAL_DATASPACE_BT601_525,
-    HAL_DATASPACE_V0_BT601_525,
-    HAL_DATASPACE_BT709,
-    HAL_DATASPACE_V0_BT709,
-    HAL_DATASPACE_DEPTH,
+const std::vector<android::ui::Dataspace> Hwc2TestDataspace::completeDataspaces = {
+    android::ui::Dataspace::UNKNOWN,
+    android::ui::Dataspace::ARBITRARY,
+    android::ui::Dataspace::STANDARD_SHIFT,
+    android::ui::Dataspace::STANDARD_MASK,
+    android::ui::Dataspace::STANDARD_UNSPECIFIED,
+    android::ui::Dataspace::STANDARD_BT709,
+    android::ui::Dataspace::STANDARD_BT601_625,
+    android::ui::Dataspace::STANDARD_BT601_625_UNADJUSTED,
+    android::ui::Dataspace::STANDARD_BT601_525,
+    android::ui::Dataspace::STANDARD_BT601_525_UNADJUSTED,
+    android::ui::Dataspace::STANDARD_BT2020,
+    android::ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE,
+    android::ui::Dataspace::STANDARD_BT470M,
+    android::ui::Dataspace::STANDARD_FILM,
+    android::ui::Dataspace::TRANSFER_SHIFT,
+    android::ui::Dataspace::TRANSFER_MASK,
+    android::ui::Dataspace::TRANSFER_UNSPECIFIED,
+    android::ui::Dataspace::TRANSFER_LINEAR,
+    android::ui::Dataspace::TRANSFER_SRGB,
+    android::ui::Dataspace::TRANSFER_SMPTE_170M,
+    android::ui::Dataspace::TRANSFER_GAMMA2_2,
+    android::ui::Dataspace::TRANSFER_GAMMA2_8,
+    android::ui::Dataspace::TRANSFER_ST2084,
+    android::ui::Dataspace::TRANSFER_HLG,
+    android::ui::Dataspace::RANGE_SHIFT,
+    android::ui::Dataspace::RANGE_MASK,
+    android::ui::Dataspace::RANGE_UNSPECIFIED,
+    android::ui::Dataspace::RANGE_FULL,
+    android::ui::Dataspace::RANGE_LIMITED,
+    android::ui::Dataspace::SRGB_LINEAR,
+    android::ui::Dataspace::V0_SRGB_LINEAR,
+    android::ui::Dataspace::SRGB,
+    android::ui::Dataspace::V0_SRGB,
+    android::ui::Dataspace::JFIF,
+    android::ui::Dataspace::V0_JFIF,
+    android::ui::Dataspace::BT601_625,
+    android::ui::Dataspace::V0_BT601_625,
+    android::ui::Dataspace::BT601_525,
+    android::ui::Dataspace::V0_BT601_525,
+    android::ui::Dataspace::BT709,
+    android::ui::Dataspace::V0_BT709,
+    android::ui::Dataspace::DEPTH,
 };
 
 
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
index cb811e0..d7082f3 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -20,6 +20,7 @@
 #include <array>
 #include <vector>
 
+#include <ui/GraphicTypes.h>
 #include <ui/Region.h>
 
 #define HWC2_INCLUDE_STRINGIFICATION
@@ -229,16 +230,16 @@
 };
 
 
-class Hwc2TestDataspace : public Hwc2TestProperty<android_dataspace_t> {
+class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> {
 public:
     Hwc2TestDataspace(Hwc2TestCoverage coverage);
 
     std::string dump() const override;
 
 protected:
-    static const std::vector<android_dataspace_t> defaultDataspaces;
-    static const std::vector<android_dataspace_t> basicDataspaces;
-    static const std::vector<android_dataspace_t> completeDataspaces;
+    static const std::vector<android::ui::Dataspace> defaultDataspaces;
+    static const std::vector<android::ui::Dataspace> basicDataspaces;
+    static const std::vector<android::ui::Dataspace> completeDataspaces;
 
     static const std::array<bool, 6> mCompositionSupport;
 };
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 353b245..8ffc5ad 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -21,10 +21,16 @@
         ":libsurfaceflinger_sources",
         "DisplayTransactionTest.cpp",
         "MockComposer.cpp",
+        "MockDisplaySurface.cpp",
+        "MockEventControlThread.cpp",
         "MockEventThread.cpp",
         "MockGraphicBufferConsumer.cpp",
         "MockGraphicBufferProducer.cpp",
+        "MockMessageQueue.cpp",
+        "MockNativeWindow.cpp",
+        "MockNativeWindowSurface.cpp",
         "MockRenderEngine.cpp",
+        "MockSurfaceInterceptor.cpp",
     ],
     static_libs: [
         "libgmock",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index fafc54e..c048c58 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -21,12 +21,19 @@
 #include <gtest/gtest.h>
 
 #include <log/log.h>
+#include "system/window.h"
 
 #include "MockComposer.h"
+#include "MockDisplaySurface.h"
+#include "MockEventControlThread.h"
 #include "MockEventThread.h"
 #include "MockGraphicBufferConsumer.h"
 #include "MockGraphicBufferProducer.h"
+#include "MockMessageQueue.h"
+#include "MockNativeWindow.h"
+#include "MockNativeWindowSurface.h"
 #include "MockRenderEngine.h"
+#include "MockSurfaceInterceptor.h"
 #include "TestableSurfaceFlinger.h"
 
 namespace android {
@@ -39,36 +46,119 @@
 using testing::Return;
 using testing::SetArgPointee;
 
+using android::hardware::graphics::common::V1_0::ColorMode;
 using android::hardware::graphics::common::V1_0::Hdr;
 using android::Hwc2::Error;
 using android::Hwc2::IComposer;
 using android::Hwc2::IComposerClient;
 
+using HWC2Display = TestableSurfaceFlinger::HWC2Display;
+using HotplugEvent = TestableSurfaceFlinger::HotplugEvent;
+
 constexpr int32_t DEFAULT_REFRESH_RATE = 1666666666;
 constexpr int32_t DEFAULT_DPI = 320;
 
+constexpr int DEFAULT_CONFIG_ID = 0;
+
 class DisplayTransactionTest : public testing::Test {
 protected:
     DisplayTransactionTest();
     ~DisplayTransactionTest() override;
 
-    void setupComposer(int virtualDisplayCount);
-    void setupPrimaryDisplay(int width, int height);
+    // --------------------------------------------------------------------
+    // Precondition helpers
 
-    void expectFramebufferQueuePairCreation(int width, int height);
+    void setupComposer(int virtualDisplayCount);
+    void setupFakeHwcDisplay(hwc2_display_t displayId, DisplayDevice::DisplayType type, int width,
+                             int height);
+
+    struct FakeDisplayDeviceFactory {
+    public:
+        FakeDisplayDeviceFactory(TestableSurfaceFlinger& flinger, sp<BBinder>& displayToken,
+                                 DisplayDevice::DisplayType type, int hwcId)
+              : mFlinger(flinger), mDisplayToken(displayToken), mType(type), mHwcId(hwcId) {}
+
+        sp<DisplayDevice> build() {
+            return new DisplayDevice(mFlinger.mFlinger.get(), mType, mHwcId, false, mDisplayToken,
+                                     mNativeWindow, mDisplaySurface, std::move(mRenderSurface), 0,
+                                     0, false, false, HWC_POWER_MODE_NORMAL);
+        }
+
+        FakeDisplayDeviceFactory& setNativeWindow(const sp<ANativeWindow>& nativeWindow) {
+            mNativeWindow = nativeWindow;
+            return *this;
+        }
+
+        FakeDisplayDeviceFactory& setDisplaySurface(const sp<DisplaySurface>& displaySurface) {
+            mDisplaySurface = displaySurface;
+            return *this;
+        }
+
+        FakeDisplayDeviceFactory& setRenderSurface(std::unique_ptr<RE::Surface> renderSurface) {
+            mRenderSurface = std::move(renderSurface);
+            return *this;
+        }
+
+        TestableSurfaceFlinger& mFlinger;
+        sp<BBinder>& mDisplayToken;
+        DisplayDevice::DisplayType mType;
+        int mHwcId;
+        sp<ANativeWindow> mNativeWindow;
+        sp<DisplaySurface> mDisplaySurface;
+        std::unique_ptr<RE::Surface> mRenderSurface;
+    };
+
+    sp<BBinder> setupFakeExistingPhysicalDisplay(hwc2_display_t displayId,
+                                                 DisplayDevice::DisplayType type);
+
+    void setupFakeBufferQueueFactory();
+    void setupFakeNativeWindowSurfaceFactory(int displayWidth, int displayHeight, bool critical,
+                                             bool async);
+    void expectFramebufferUsageSet(int width, int height, int grallocUsage);
+    void expectHwcHotplugCalls(hwc2_display_t displayId, int displayWidth, int displayHeight);
+
+    // --------------------------------------------------------------------
+    // Call expectation helpers
+
+    void expectRESurfaceCreationCalls();
+    void expectPhysicalDisplayDeviceCreationCalls(hwc2_display_t displayId, int displayWidth,
+                                                  int displayHeight, bool critical, bool async);
+
+    // --------------------------------------------------------------------
+    // Postcondition helpers
+
+    bool hasTransactionFlagSet(int flag);
+    bool hasDisplayDevice(sp<IBinder> displayToken);
+    sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
+    bool hasCurrentDisplayState(sp<IBinder> displayToken);
+    const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
+    bool hasDrawingDisplayState(sp<IBinder> displayToken);
+    const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
+
+    // --------------------------------------------------------------------
+    // Test instances
+
+    std::unordered_set<HWC2::Capability> mCapabilities;
 
     TestableSurfaceFlinger mFlinger;
     mock::EventThread* mEventThread = new mock::EventThread();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
 
     // These mocks are created by the test, but are destroyed by SurfaceFlinger
     // by virtue of being stored into a std::unique_ptr. However we still need
     // to keep a reference to them for use in setting up call expectations.
     RE::mock::RenderEngine* mRenderEngine = new RE::mock::RenderEngine();
     Hwc2::mock::Composer* mComposer = new Hwc2::mock::Composer();
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
 
     // These mocks are created only when expected to be created via a factory.
     sp<mock::GraphicBufferConsumer> mConsumer;
     sp<mock::GraphicBufferProducer> mProducer;
+    mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
+    sp<mock::NativeWindow> mNativeWindow;
+    RE::mock::Surface* mRenderSurface = nullptr;
+    std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
 };
 
 DisplayTransactionTest::DisplayTransactionTest() {
@@ -80,8 +170,16 @@
         ADD_FAILURE() << "Unexpected request to create a buffer queue.";
     });
 
+    mFlinger.setCreateNativeWindowSurface([](auto) {
+        ADD_FAILURE() << "Unexpected request to create a native window surface.";
+        return nullptr;
+    });
+
+    mFlinger.mutableEventControlThread().reset(mEventControlThread);
     mFlinger.mutableEventThread().reset(mEventThread);
+    mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine));
+    mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
 
     setupComposer(0);
 }
@@ -101,40 +199,49 @@
     Mock::VerifyAndClear(mComposer);
 }
 
-void DisplayTransactionTest::setupPrimaryDisplay(int width, int height) {
-    EXPECT_CALL(*mComposer, getDisplayType(DisplayDevice::DISPLAY_PRIMARY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                            Return(Error::NONE)));
-    EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
-    EXPECT_CALL(*mComposer, getDisplayConfigs(_, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{0}), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer,
-                getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0,
-                                    IComposerClient::Attribute::WIDTH, _))
-            .WillOnce(DoAll(SetArgPointee<3>(width), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer,
-                getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0,
-                                    IComposerClient::Attribute::HEIGHT, _))
-            .WillOnce(DoAll(SetArgPointee<3>(height), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer,
-                getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0,
-                                    IComposerClient::Attribute::VSYNC_PERIOD, _))
-            .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer,
-                getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0,
-                                    IComposerClient::Attribute::DPI_X, _))
-            .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer,
-                getDisplayAttribute(DisplayDevice::DISPLAY_PRIMARY, 0,
-                                    IComposerClient::Attribute::DPI_Y, _))
-            .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+void DisplayTransactionTest::setupFakeHwcDisplay(hwc2_display_t displayId,
+                                                 DisplayDevice::DisplayType type, int width,
+                                                 int height) {
+    auto display = std::make_unique<HWC2Display>(*mComposer, mCapabilities, displayId,
+                                                 HWC2::DisplayType::Physical);
+    display->mutableIsConnected() = true;
+    display->mutableConfigs().emplace(DEFAULT_CONFIG_ID,
+                                      HWC2::Display::Config::Builder(*display, DEFAULT_CONFIG_ID)
+                                              .setWidth(width)
+                                              .setHeight(height)
+                                              .setVsyncPeriod(DEFAULT_REFRESH_RATE)
+                                              .setDpiX(DEFAULT_DPI)
+                                              .setDpiY(DEFAULT_DPI)
+                                              .build());
 
-    mFlinger.setupPrimaryDisplay();
+    mFlinger.mutableHwcDisplayData()[type].reset();
+    mFlinger.mutableHwcDisplayData()[type].hwcDisplay = display.get();
+    mFlinger.mutableHwcDisplaySlots().emplace(displayId, type);
 
-    Mock::VerifyAndClear(mComposer);
+    mFakeHwcDisplays.push_back(std::move(display));
 }
 
-void DisplayTransactionTest::expectFramebufferQueuePairCreation(int width, int height) {
+sp<BBinder> DisplayTransactionTest::setupFakeExistingPhysicalDisplay(
+        hwc2_display_t displayId, DisplayDevice::DisplayType type) {
+    setupFakeHwcDisplay(displayId, type, 0, 0);
+
+    sp<BBinder> displayToken = new BBinder();
+    mFlinger.mutableBuiltinDisplays()[type] = displayToken;
+    mFlinger.mutableDisplays()
+            .add(displayToken,
+                 FakeDisplayDeviceFactory(mFlinger, displayToken, type, type).build());
+
+    DisplayDeviceState state(type, true);
+    mFlinger.mutableCurrentState().displays.add(displayToken, state);
+    mFlinger.mutableDrawingState().displays.add(displayToken, state);
+
+    return displayToken;
+}
+
+void DisplayTransactionTest::setupFakeBufferQueueFactory() {
+    // This setup is only expected once per test.
+    ASSERT_TRUE(mConsumer == nullptr && mProducer == nullptr);
+
     mConsumer = new mock::GraphicBufferConsumer();
     mProducer = new mock::GraphicBufferProducer();
 
@@ -142,66 +249,187 @@
         *outProducer = mProducer;
         *outConsumer = mConsumer;
     });
+}
 
+void DisplayTransactionTest::setupFakeNativeWindowSurfaceFactory(int displayWidth,
+                                                                 int displayHeight, bool critical,
+                                                                 bool async) {
+    // This setup is only expected once per test.
+    ASSERT_TRUE(mNativeWindowSurface == nullptr);
+
+    mNativeWindowSurface = new mock::NativeWindowSurface();
+    mNativeWindow = new mock::NativeWindow();
+
+    mFlinger.setCreateNativeWindowSurface(
+            [this](auto) { return std::unique_ptr<NativeWindowSurface>(mNativeWindowSurface); });
+
+    EXPECT_CALL(*mNativeWindowSurface, getNativeWindow()).WillOnce(Return(mNativeWindow));
+
+    EXPECT_CALL(*mNativeWindow, perform(19)).Times(1);
+
+    EXPECT_CALL(*mRenderSurface, setAsync(async)).Times(1);
+    EXPECT_CALL(*mRenderSurface, setCritical(critical)).Times(1);
+    EXPECT_CALL(*mRenderSurface, setNativeWindow(mNativeWindow.get())).Times(1);
+    EXPECT_CALL(*mRenderSurface, queryWidth()).WillOnce(Return(displayWidth));
+    EXPECT_CALL(*mRenderSurface, queryHeight()).WillOnce(Return(displayHeight));
+}
+
+void DisplayTransactionTest::expectFramebufferUsageSet(int width, int height, int grallocUsage) {
     EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
     EXPECT_CALL(*mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
-    EXPECT_CALL(*mConsumer,
-                setConsumerUsageBits(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER |
-                                     GRALLOC_USAGE_HW_FB))
-            .WillRepeatedly(Return(NO_ERROR));
+    EXPECT_CALL(*mConsumer, setConsumerUsageBits(grallocUsage)).WillRepeatedly(Return(NO_ERROR));
     EXPECT_CALL(*mConsumer, setDefaultBufferSize(width, height)).WillRepeatedly(Return(NO_ERROR));
     EXPECT_CALL(*mConsumer, setMaxAcquiredBufferCount(_)).WillRepeatedly(Return(NO_ERROR));
 
     EXPECT_CALL(*mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
 }
 
-TEST_F(DisplayTransactionTest, processDisplayChangesLockedProcessesPrimaryDisplayConnected) {
-    using android::hardware::graphics::common::V1_0::ColorMode;
-
-    setupPrimaryDisplay(1920, 1080);
-
-    sp<BBinder> token = new BBinder();
-    mFlinger.mutableCurrentState().displays.add(token, {DisplayDevice::DISPLAY_PRIMARY, true});
-
-    EXPECT_CALL(*mComposer, getActiveConfig(DisplayDevice::DISPLAY_PRIMARY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(0), Return(Error::NONE)));
-    EXPECT_CALL(*mComposer, getColorModes(DisplayDevice::DISPLAY_PRIMARY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::NATIVE})),
+void DisplayTransactionTest::expectHwcHotplugCalls(hwc2_display_t displayId, int displayWidth,
+                                                   int displayHeight) {
+    EXPECT_CALL(*mComposer, getDisplayType(displayId, _))
+            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
                             Return(Error::NONE)));
-    EXPECT_CALL(*mComposer, getHdrCapabilities(DisplayDevice::DISPLAY_PRIMARY, _, _, _, _))
+    EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mComposer, getDisplayConfigs(_, _))
+            .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{0}), Return(Error::NONE)));
+    EXPECT_CALL(*mComposer, getDisplayAttribute(displayId, 0, IComposerClient::Attribute::WIDTH, _))
+            .WillOnce(DoAll(SetArgPointee<3>(displayWidth), Return(Error::NONE)));
+    EXPECT_CALL(*mComposer,
+                getDisplayAttribute(displayId, 0, IComposerClient::Attribute::HEIGHT, _))
+            .WillOnce(DoAll(SetArgPointee<3>(displayHeight), Return(Error::NONE)));
+    EXPECT_CALL(*mComposer,
+                getDisplayAttribute(displayId, 0, IComposerClient::Attribute::VSYNC_PERIOD, _))
+            .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+    EXPECT_CALL(*mComposer, getDisplayAttribute(displayId, 0, IComposerClient::Attribute::DPI_X, _))
+            .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+    EXPECT_CALL(*mComposer, getDisplayAttribute(displayId, 0, IComposerClient::Attribute::DPI_Y, _))
+            .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+}
+
+void DisplayTransactionTest::expectRESurfaceCreationCalls() {
+    // This setup is only expected once per test.
+    ASSERT_TRUE(mRenderSurface == nullptr);
+
+    mRenderSurface = new RE::mock::Surface();
+    EXPECT_CALL(*mRenderEngine, createSurface())
+            .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(mRenderSurface))));
+}
+
+void DisplayTransactionTest::expectPhysicalDisplayDeviceCreationCalls(hwc2_display_t displayId,
+                                                                      int displayWidth,
+                                                                      int displayHeight,
+                                                                      bool critical, bool async) {
+    EXPECT_CALL(*mComposer, getActiveConfig(displayId, _))
+            .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
+    EXPECT_CALL(*mComposer, getColorModes(displayId, _)).Times(0);
+    EXPECT_CALL(*mComposer, getHdrCapabilities(displayId, _, _, _, _))
             .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
 
-    expectFramebufferQueuePairCreation(1920, 1080);
+    setupFakeBufferQueueFactory();
+    expectFramebufferUsageSet(displayWidth, displayHeight,
+                              GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER |
+                                      GRALLOC_USAGE_HW_FB);
 
-    auto reSurface = new RE::mock::Surface();
-    EXPECT_CALL(*mRenderEngine, createSurface())
-            .WillOnce(Return(ByMove(std::unique_ptr<RE::Surface>(reSurface))));
-    EXPECT_CALL(*reSurface, setAsync(false)).Times(1);
-    EXPECT_CALL(*reSurface, setCritical(true)).Times(1);
-    EXPECT_CALL(*reSurface, setNativeWindow(_)).Times(1);
-    EXPECT_CALL(*reSurface, queryWidth()).WillOnce(Return(1920));
-    EXPECT_CALL(*reSurface, queryHeight()).WillOnce(Return(1080));
+    setupFakeNativeWindowSurfaceFactory(displayWidth, displayHeight, critical, async);
+}
+
+bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
+    return mFlinger.mutableTransactionFlags() & flag;
+}
+
+bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) {
+    return mFlinger.mutableDisplays().indexOfKey(displayToken) >= 0;
+}
+
+sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) {
+    return mFlinger.mutableDisplays().valueFor(displayToken);
+}
+
+bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableCurrentState().displays.indexOfKey(displayToken) >= 0;
+}
+
+const DisplayDeviceState& DisplayTransactionTest::getCurrentDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableCurrentState().displays.valueFor(displayToken);
+}
+
+bool DisplayTransactionTest::hasDrawingDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableDrawingState().displays.indexOfKey(displayToken) >= 0;
+}
+
+const DisplayDeviceState& DisplayTransactionTest::getDrawingDisplayState(sp<IBinder> displayToken) {
+    return mFlinger.mutableDrawingState().displays.valueFor(displayToken);
+}
+
+/* ------------------------------------------------------------------------
+ * SurfaceFlinger::handleTransactionLocked(eDisplayTransactionNeeded)
+ */
+
+TEST_F(DisplayTransactionTest, handleTransactionLockedProcessesHotplugConnectPrimary) {
+    constexpr hwc2_display_t externalDisplayId = 102;
+    constexpr hwc2_display_t displayId = 123;
+    constexpr int displayWidth = 1920;
+    constexpr int displayHeight = 1080;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // An external display may already be set up
+    setupFakeHwcDisplay(externalDisplayId, DisplayDevice::DISPLAY_EXTERNAL, 3840, 2160);
+
+    // A hotplug connect comes in for a new display
+    mFlinger.mutablePendingHotplugEvents().emplace_back(
+            HotplugEvent{displayId, HWC2::Connection::Connected});
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillOnce(Return(false));
+    expectHwcHotplugCalls(displayId, displayWidth, displayHeight);
+    expectRESurfaceCreationCalls();
+    expectPhysicalDisplayDeviceCreationCalls(displayId, displayWidth, displayHeight, true, false);
+
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
 
     EXPECT_CALL(*mEventThread, onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, true)).Times(1);
 
-    mFlinger.processDisplayChangesLocked();
+    // --------------------------------------------------------------------
+    // Invocation
 
-    ASSERT_TRUE(mFlinger.mutableDisplays().indexOfKey(token) >= 0);
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
 
-    const auto& device = mFlinger.mutableDisplays().valueFor(token);
-    ASSERT_TRUE(device.get());
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should have an entry for the display
+    EXPECT_TRUE(mFlinger.mutableHwcDisplaySlots().count(displayId) == 1);
+
+    // The display should have set up as a primary built-in display.
+    auto displayToken = mFlinger.mutableBuiltinDisplays()[DisplayDevice::DISPLAY_PRIMARY];
+    ASSERT_TRUE(displayToken != nullptr);
+
+    // The display device should have been set up in the list of displays.
+    ASSERT_TRUE(hasDisplayDevice(displayToken));
+    const auto& device = getDisplayDevice(displayToken);
     EXPECT_TRUE(device->isSecure());
     EXPECT_TRUE(device->isPrimary());
 
-    ssize_t i = mFlinger.mutableDrawingState().displays.indexOfKey(token);
-    ASSERT_GE(0, i);
-    const auto& draw = mFlinger.mutableDrawingState().displays[i];
+    // The display should have been set up in the current display state
+    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+    const auto& current = getCurrentDisplayState(displayToken);
+    EXPECT_EQ(DisplayDevice::DISPLAY_PRIMARY, current.type);
+
+    // The display should have been set up in the drawing display state
+    ASSERT_TRUE(hasDrawingDisplayState(displayToken));
+    const auto& draw = getDrawingDisplayState(displayToken);
     EXPECT_EQ(DisplayDevice::DISPLAY_PRIMARY, draw.type);
 
-    EXPECT_CALL(*mComposer, setVsyncEnabled(0, IComposerClient::Vsync::DISABLE))
-            .WillOnce(Return(Error::NONE));
+    // --------------------------------------------------------------------
+    // Cleanup conditions
 
-    EXPECT_CALL(*mConsumer, consumerDisconnect()).Times(1);
+    EXPECT_CALL(*mComposer, setVsyncEnabled(displayId, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/MockComposer.h b/services/surfaceflinger/tests/unittests/MockComposer.h
index acd9b30..00e565b 100644
--- a/services/surfaceflinger/tests/unittests/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/MockComposer.h
@@ -29,10 +29,10 @@
 
 using android::hardware::graphics::common::V1_0::ColorMode;
 using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Dataspace;
 using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::PixelFormat;
 
 using android::hardware::graphics::composer::V2_1::Config;
 using android::hardware::graphics::composer::V2_1::Display;
diff --git a/services/surfaceflinger/tests/unittests/MockDisplaySurface.cpp b/services/surfaceflinger/tests/unittests/MockDisplaySurface.cpp
new file mode 100644
index 0000000..507626b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockDisplaySurface.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "MockDisplaySurface.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+DisplaySurface::DisplaySurface() = default;
+DisplaySurface::~DisplaySurface() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockDisplaySurface.h b/services/surfaceflinger/tests/unittests/MockDisplaySurface.h
new file mode 100644
index 0000000..d6c9aa4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockDisplaySurface.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <utils/String8.h>
+
+#include "DisplayHardware/DisplaySurface.h"
+
+namespace android {
+namespace mock {
+
+class DisplaySurface : public android::DisplaySurface {
+public:
+    DisplaySurface();
+    ~DisplaySurface() override;
+
+    MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
+    MOCK_METHOD1(prepareFrame, status_t(CompositionType compositionType));
+    MOCK_METHOD0(advanceFrame, status_t());
+    MOCK_METHOD0(onFrameCommitted, void());
+    MOCK_CONST_METHOD1(dumpAsString, void(String8& result));
+    MOCK_METHOD2(resizeBuffers, void(uint32_t, uint32_t));
+    MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockEventControlThread.cpp b/services/surfaceflinger/tests/unittests/MockEventControlThread.cpp
new file mode 100644
index 0000000..398fd42
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockEventControlThread.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "MockEventControlThread.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+EventControlThread::EventControlThread() = default;
+EventControlThread::~EventControlThread() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockEventControlThread.h b/services/surfaceflinger/tests/unittests/MockEventControlThread.h
new file mode 100644
index 0000000..8ac09a9
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockEventControlThread.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "EventControlThread.h"
+
+namespace android {
+namespace mock {
+
+class EventControlThread : public android::EventControlThread {
+public:
+    EventControlThread();
+    ~EventControlThread() override;
+
+    MOCK_METHOD1(setVsyncEnabled, void(bool));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/MockMessageQueue.cpp
new file mode 100644
index 0000000..62f45ed
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockMessageQueue.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "MockMessageQueue.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+MessageQueue::MessageQueue() = default;
+MessageQueue::~MessageQueue() = default;
+
+} // namespace mock
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/MockMessageQueue.h
new file mode 100644
index 0000000..cf07cf7
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockMessageQueue.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "MessageQueue.h"
+
+namespace android {
+namespace mock {
+
+class MessageQueue : public android::MessageQueue {
+public:
+    MessageQueue();
+    ~MessageQueue() override;
+
+    MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
+    MOCK_METHOD1(setEventThread, void(android::EventThread*));
+    MOCK_METHOD0(waitMessage, void());
+    MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
+    MOCK_METHOD0(invalidate, void());
+    MOCK_METHOD0(refresh, void());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindow.cpp b/services/surfaceflinger/tests/unittests/MockNativeWindow.cpp
new file mode 100644
index 0000000..61038f4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockNativeWindow.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "MockNativeWindow.h"
+
+namespace android {
+namespace mock {
+namespace {
+
+int dispatch_setSwapInterval(struct ANativeWindow* window, int interval) {
+    return static_cast<NativeWindow*>(window)->setSwapInterval(interval);
+}
+
+int dispatch_dequeueBuffer_DEPRECATED(struct ANativeWindow* window,
+                                      struct ANativeWindowBuffer** buffer) {
+    return static_cast<NativeWindow*>(window)->dequeueBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_lockBuffer_DEPRECATED(struct ANativeWindow* window,
+                                   struct ANativeWindowBuffer* buffer) {
+    return static_cast<NativeWindow*>(window)->lockBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_queueBuffer_DEPRECATED(struct ANativeWindow* window,
+                                    struct ANativeWindowBuffer* buffer) {
+    return static_cast<NativeWindow*>(window)->queueBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_query(const struct ANativeWindow* window, int what, int* value) {
+    return static_cast<const NativeWindow*>(window)->query(what, value);
+}
+
+int dispatch_perform(struct ANativeWindow* window, int operation, ...) {
+    // TODO: Handle the various operations and their varargs better.
+    return static_cast<NativeWindow*>(window)->perform(operation);
+}
+
+int dispatch_cancelBuffer_DEPRECATED(struct ANativeWindow* window,
+                                     struct ANativeWindowBuffer* buffer) {
+    return static_cast<NativeWindow*>(window)->cancelBuffer_DEPRECATED(buffer);
+}
+
+int dispatch_dequeueBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer,
+                           int* fenceFd) {
+    return static_cast<NativeWindow*>(window)->dequeueBuffer(buffer, fenceFd);
+}
+
+int dispatch_queueBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer,
+                         int fenceFd) {
+    return static_cast<NativeWindow*>(window)->queueBuffer(buffer, fenceFd);
+}
+
+int dispatch_cancelBuffer(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer,
+                          int fenceFd) {
+    return static_cast<NativeWindow*>(window)->cancelBuffer(buffer, fenceFd);
+}
+
+} // namespace
+
+NativeWindow::NativeWindow() {
+    // ANativeWindow is a structure with function pointers and not a C++ class.
+    // Set all the pointers to dispatch functions, which will invoke the mock
+    // interface functions.
+    ANativeWindow::setSwapInterval = &dispatch_setSwapInterval;
+    ANativeWindow::dequeueBuffer_DEPRECATED = &dispatch_dequeueBuffer_DEPRECATED;
+    ANativeWindow::lockBuffer_DEPRECATED = &dispatch_lockBuffer_DEPRECATED;
+    ANativeWindow::queueBuffer_DEPRECATED = &dispatch_queueBuffer_DEPRECATED;
+    ANativeWindow::query = &dispatch_query;
+    ANativeWindow::perform = &dispatch_perform;
+    ANativeWindow::cancelBuffer_DEPRECATED = &dispatch_cancelBuffer_DEPRECATED;
+    ANativeWindow::dequeueBuffer = &dispatch_dequeueBuffer;
+    ANativeWindow::queueBuffer = &dispatch_queueBuffer;
+    ANativeWindow::cancelBuffer = &dispatch_cancelBuffer;
+}
+
+// Explicit default instantiation is recommended.
+NativeWindow::~NativeWindow() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/MockNativeWindow.h
new file mode 100644
index 0000000..561fd58
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockNativeWindow.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <system/window.h>
+
+#include <ui/ANativeObjectBase.h>
+
+namespace android {
+namespace mock {
+
+class NativeWindow : public ANativeObjectBase<ANativeWindow, NativeWindow, RefBase> {
+public:
+    NativeWindow();
+    ~NativeWindow();
+
+    MOCK_METHOD1(setSwapInterval, int(int interval));
+    MOCK_METHOD1(dequeueBuffer_DEPRECATED, int(struct ANativeWindowBuffer**));
+    MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_CONST_METHOD2(query, int(int, int*));
+    MOCK_METHOD1(perform, int(int));
+    MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+    MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
+    MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
+    MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.cpp b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.cpp
new file mode 100644
index 0000000..0314568
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "MockNativeWindowSurface.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+NativeWindowSurface::NativeWindowSurface() = default;
+NativeWindowSurface::~NativeWindowSurface() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.h b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.h
new file mode 100644
index 0000000..88d1a9f
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockNativeWindowSurface.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <system/window.h> // for ANativeWindow
+
+#include "SurfaceFlinger.h" // for base NativeWindowSurface
+
+namespace android {
+namespace mock {
+
+class NativeWindowSurface : public android::NativeWindowSurface {
+public:
+    NativeWindowSurface();
+    ~NativeWindowSurface();
+
+    MOCK_CONST_METHOD0(getNativeWindow, sp<ANativeWindow>());
+    MOCK_METHOD0(preallocateBuffers, void());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
index 6d3e17f..9bb2a3c 100644
--- a/services/surfaceflinger/tests/unittests/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
@@ -64,8 +64,8 @@
     MOCK_METHOD0(disableTexturing, void());
     MOCK_METHOD0(disableBlending, void());
     MOCK_METHOD1(setSourceY410BT2020, void(bool));
-    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
-    MOCK_METHOD1(setOutputDataSpace, void(android_dataspace));
+    MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
+    MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
     MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
                  void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
     MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));
diff --git a/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.cpp
new file mode 100644
index 0000000..b2ec721
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 "MockSurfaceInterceptor.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+SurfaceInterceptor::SurfaceInterceptor() = default;
+SurfaceInterceptor::~SurfaceInterceptor() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.h
new file mode 100644
index 0000000..458b2f3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MockSurfaceInterceptor.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "SurfaceInterceptor.h"
+
+namespace android {
+namespace mock {
+
+class SurfaceInterceptor : public android::SurfaceInterceptor {
+public:
+    SurfaceInterceptor();
+    ~SurfaceInterceptor() override;
+
+    MOCK_METHOD2(enable,
+                 void(const SortedVector<sp<Layer>>&,
+                      const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
+    MOCK_METHOD0(disable, void());
+    MOCK_METHOD0(isEnabled, bool());
+    MOCK_METHOD4(saveTransaction,
+                 void(const Vector<ComposerState>&,
+                      const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,
+                      const Vector<DisplayState>&, uint32_t));
+    MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
+    MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
+    MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t));
+    MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
+    MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
+    MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));
+    MOCK_METHOD1(saveVSyncEvent, void(nsecs_t));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4895e16..2dd8e5f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -44,33 +44,44 @@
         mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer)));
     }
 
-    void setupPrimaryDisplay() {
-        mFlinger->getBE().mHwc->mHwcDevice->onHotplug(0, HWC2::Connection::Connected);
-        mFlinger->getBE().mHwc->onHotplug(0, DisplayDevice::DISPLAY_PRIMARY,
-                                          HWC2::Connection::Connected);
-    }
-
     using CreateBufferQueueFunction = SurfaceFlinger::CreateBufferQueueFunction;
-
     void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
         mFlinger->mCreateBufferQueue = f;
     }
 
+    using CreateNativeWindowSurfaceFunction = SurfaceFlinger::CreateNativeWindowSurfaceFunction;
+    void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) {
+        mFlinger->mCreateNativeWindowSurface = f;
+    }
+
+    using HotplugEvent = SurfaceFlinger::HotplugEvent;
+
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
-    auto processDisplayChangesLocked() { return mFlinger->processDisplayChangesLocked(); }
+
+    auto handleTransactionLocked(uint32_t transactionFlags) {
+        return mFlinger->handleTransactionLocked(transactionFlags);
+    }
 
     /* ------------------------------------------------------------------------
      * Read-write access to private data to set up preconditions and assert
      * post-conditions.
      */
+
     auto& mutableBuiltinDisplays() { return mFlinger->mBuiltinDisplays; }
-    auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
+    auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
-    auto& mutableEventThread() { return mFlinger->mEventThread; }
+    auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
     auto& mutableEventQueue() { return mFlinger->mEventQueue; }
+    auto& mutableEventThread() { return mFlinger->mEventThread; }
+    auto& mutableInterceptor() { return mFlinger->mInterceptor; }
+    auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+    auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
+
+    auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; }
+    auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; }
 
     ~TestableSurfaceFlinger() {
         // All these pointer and container clears help ensure that GMock does
@@ -78,12 +89,33 @@
         // still be referenced by something despite our best efforts to destroy
         // it after each test is done.
         mutableDisplays().clear();
+        mutableEventControlThread().reset();
+        mutableEventQueue().reset();
         mutableEventThread().reset();
+        mutableInterceptor().reset();
         mFlinger->getBE().mHwc.reset();
         mFlinger->getBE().mRenderEngine.reset();
     }
 
-    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger();
+    /* ------------------------------------------------------------------------
+     * Wrapper classes for Read-write access to private data to set up
+     * preconditions and assert post-conditions.
+     */
+    struct HWC2Display : public HWC2::Display {
+        HWC2Display(Hwc2::Composer& composer,
+                    const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
+                    HWC2::DisplayType type)
+              : HWC2::Display(composer, capabilities, id, type) {}
+        ~HWC2Display() {
+            // Prevents a call to disable vsyncs.
+            mType = HWC2::DisplayType::Invalid;
+        }
+
+        auto& mutableIsConnected() { return this->mIsConnected; }
+        auto& mutableConfigs() { return this->mConfigs; }
+    };
+
+    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
 };
 
 } // namespace android
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
new file mode 100644
index 0000000..6122846
--- /dev/null
+++ b/services/vr/bufferhubd/Android.bp
@@ -0,0 +1,56 @@
+// Copyright (C) 2016 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.
+
+sourceFiles = [
+    "buffer_hub.cpp",
+    "bufferhubd.cpp",
+    "consumer_channel.cpp",
+    "producer_channel.cpp",
+    "detached_buffer_channel.cpp",
+    "consumer_queue_channel.cpp",
+    "producer_queue_channel.cpp",
+]
+
+headerLibraries = ["libdvr_headers"]
+
+staticLibraries = [
+    "libperformance",
+    "libbufferhub",
+]
+
+sharedLibraries = [
+    "libbase",
+    "libbinder",
+    "libcutils",
+    "liblog",
+    "libsync",
+    "libutils",
+    "libgui",
+    "libui",
+    "libpdx_default_transport",
+]
+
+cc_binary {
+    srcs: sourceFiles,
+    cflags: [
+        "-DLOG_TAG=\"bufferhubd\"",
+        "-DTRACE=0",
+        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+    ],
+    header_libs: headerLibraries,
+    static_libs: staticLibraries,
+    shared_libs: sharedLibraries,
+    name: "bufferhubd",
+    init_rc: ["bufferhubd.rc"],
+}
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
deleted file mode 100644
index 1a99cf4..0000000
--- a/services/vr/bufferhubd/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-sourceFiles := \
-    buffer_hub.cpp \
-    bufferhubd.cpp \
-    consumer_channel.cpp \
-    producer_channel.cpp \
-    consumer_queue_channel.cpp \
-    producer_queue_channel.cpp \
-
-headerLibraries := \
-	libdvr_headers
-
-staticLibraries := \
-	libperformance \
-	libbufferhub
-
-sharedLibraries := \
-	libbase \
-	libbinder \
-	libcutils \
-	liblog \
-	libsync \
-	libutils \
-        libgui \
-        libui \
-	libpdx_default_transport \
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(sourceFiles)
-LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\"
-LOCAL_CFLAGS += -DTRACE=0
-LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS
-LOCAL_HEADER_LIBRARIES := $(headerLibraries)
-LOCAL_STATIC_LIBRARIES := $(staticLibraries)
-LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
-LOCAL_MODULE := bufferhubd
-LOCAL_INIT_RC := bufferhubd.rc
-include $(BUILD_EXECUTABLE)
-
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 1eb4ef9..e4e19c7 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -100,6 +100,41 @@
       stream << std::setw(8) << info.index;
       stream << std::endl;
     }
+
+    if (channel->channel_type() == BufferHubChannel::kDetachedBufferType) {
+      BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
+
+      stream << std::right;
+      stream << std::setw(6) << info.id;
+      stream << " ";
+      stream << std::setw(9) << "N/A";
+      stream << " ";
+      if (info.format == HAL_PIXEL_FORMAT_BLOB) {
+        std::string size = std::to_string(info.width) + " B";
+        stream << std::setw(14) << size;
+      } else {
+        std::string dimensions = std::to_string(info.width) + "x" +
+                                 std::to_string(info.height) + "x" +
+                                 std::to_string(info.layer_count);
+        stream << std::setw(14) << dimensions;
+      }
+      stream << " ";
+      stream << std::setw(6) << info.format;
+      stream << " ";
+      stream << "0x" << std::hex << std::setfill('0');
+      stream << std::setw(8) << info.usage;
+      stream << std::dec << std::setfill(' ');
+      stream << " ";
+      stream << std::setw(9) << "N/A";
+      stream << " ";
+      stream << std::hex << std::setfill(' ');
+      stream << std::setw(18) << "Detached";
+      stream << " ";
+      stream << std::setw(18) << "N/A";
+      stream << " ";
+      stream << std::setw(10) << "N/A";
+      stream << std::endl;
+    }
   }
 
   stream << std::endl;
@@ -215,6 +250,15 @@
           *this, &BufferHubService::OnCreateProducerQueue, message);
       return {};
 
+    case BufferHubRPC::ProducerBufferDetach::Opcode:
+      // In addition to the message handler in the ProducerChannel's
+      // HandleMessage method, we also need to invalid the producer channel (and
+      // all associated consumer channels). Note that this has to be done after
+      // HandleMessage returns to make sure the IPC request has went back to the
+      // client first.
+      SetChannel(channel->channel_id(), nullptr);
+      return {};
+
     default:
       return DefaultHandleMessage(message);
   }
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index b487b0b..e04967a 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -23,6 +23,7 @@
   enum ChannelType {
     kProducerType,
     kConsumerType,
+    kDetachedBufferType,
     kProducerQueueType,
     kConsumerQueueType,
   };
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
new file mode 100644
index 0000000..edb2111
--- /dev/null
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -0,0 +1,57 @@
+#include "detached_buffer_channel.h"
+
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
+                                             int buffer_id, int channel_id,
+                                             IonBuffer buffer,
+                                             IonBuffer metadata_buffer,
+                                             size_t user_metadata_size)
+    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+      buffer_(std::move(buffer)),
+      metadata_buffer_(std::move(metadata_buffer)),
+      user_metadata_size_(user_metadata_size) {}
+
+BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
+  return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
+                    buffer_.height(), buffer_.layer_count(), buffer_.format(),
+                    buffer_.usage(), /*pending_count=*/0, /*state=*/0,
+                    /*signaled_mask=*/0, /*index=*/0);
+}
+
+void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
+  ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
+}
+
+bool DetachedBufferChannel::HandleMessage(Message& message) {
+  ATRACE_NAME("DetachedBufferChannel::HandleMessage");
+  switch (message.GetOp()) {
+    case BufferHubRPC::DetachedBufferPromote::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::DetachedBufferPromote>(
+          *this, &DetachedBufferChannel::OnPromote, message);
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
+    Message& /*message*/) {
+  ATRACE_NAME("DetachedBufferChannel::OnPromote");
+  ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
+           buffer_id());
+
+  // TODO(b/69982239): Implement the logic to promote a detached buffer.
+  return ErrorStatus(ENOSYS);
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
new file mode 100644
index 0000000..7ce4aed
--- /dev/null
+++ b/services/vr/bufferhubd/detached_buffer_channel.h
@@ -0,0 +1,43 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+
+// #include <pdx/channel_handle.h>
+// #include <pdx/file_handle.h>
+// #include <pdx/rpc/buffer_wrapper.h>
+// #include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class DetachedBufferChannel : public BufferHubChannel {
+ public:
+  // Creates a detached buffer.
+  DetachedBufferChannel(BufferHubService* service, int buffer_id,
+                        int channel_id, IonBuffer buffer,
+                        IonBuffer metadata_buffer, size_t user_metadata_size);
+
+  size_t user_metadata_size() const { return user_metadata_size_; }
+
+  // Captures buffer info for use by BufferHubService::DumpState().
+  BufferInfo GetBufferInfo() const override;
+
+  bool HandleMessage(pdx::Message& message) override;
+  void HandleImpulse(pdx::Message& message) override;
+
+ private:
+  pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+  // Gralloc buffer handles.
+  IonBuffer buffer_;
+  IonBuffer metadata_buffer_;
+
+  // Size of user requested metadata.
+  const size_t user_metadata_size_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 8160193..c38c12b 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -13,6 +13,7 @@
 
 #include <private/dvr/bufferhub_rpc.h>
 #include "consumer_channel.h"
+#include "detached_buffer_channel.h"
 
 using android::pdx::BorrowedHandle;
 using android::pdx::ErrorStatus;
@@ -131,8 +132,10 @@
            "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
            "state=%" PRIx64 ".",
            channel_id(), buffer_id(), buffer_state_->load());
-  for (auto consumer : consumer_channels_)
+  for (auto consumer : consumer_channels_) {
     consumer->OnProducerClosed();
+  }
+  Hangup();
 }
 
 BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
@@ -183,6 +186,11 @@
           *this, &ProducerChannel::OnProducerGain, message);
       return true;
 
+    case BufferHubRPC::ProducerBufferDetach::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::ProducerBufferDetach>(
+          *this, &ProducerChannel::OnProducerDetach, message);
+      return true;
+
     default:
       return false;
   }
@@ -337,6 +345,55 @@
   return {std::move(returned_fence_)};
 }
 
+Status<RemoteChannelHandle> ProducerChannel::OnProducerDetach(
+    Message& message) {
+  ATRACE_NAME("ProducerChannel::OnProducerDetach");
+  ALOGD_IF(TRACE, "ProducerChannel::OnProducerDetach: buffer_id=%d",
+           buffer_id());
+
+  uint64_t buffer_state = buffer_state_->load();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Can only detach a BufferProducer when it's in gained state.
+    ALOGW(
+        "ProducerChannel::OnProducerDetach: The buffer (id=%d, state=0x%" PRIx64
+        ") is not in gained state.",
+        buffer_id(), buffer_state);
+    return {};
+  }
+
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "ProducerChannel::OnProducerDetach: Failed to push detached buffer "
+        "channel: %s",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  // Make sure we unlock the buffer.
+  if (int ret = metadata_buffer_.Unlock()) {
+    ALOGE("ProducerChannel::OnProducerDetach: Failed to unlock metadata.");
+    return ErrorStatus(-ret);
+  };
+
+  auto channel = std::make_shared<DetachedBufferChannel>(
+      service(), buffer_id(), channel_id, std::move(buffer_),
+      std::move(metadata_buffer_), user_metadata_size_);
+
+  const auto channel_status = service()->SetChannel(channel_id, channel);
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "ProducerChannel::OnProducerDetach: Failed to set new detached buffer "
+        "channel: %s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
 Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
   ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index c5dbf0e..de9ff31 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -99,6 +99,7 @@
   pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
   pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
   pdx::Status<LocalFence> OnProducerGain(Message& message);
+  pdx::Status<RemoteChannelHandle> OnProducerDetach(Message& message);
 
   ProducerChannel(const ProducerChannel&) = delete;
   void operator=(const ProducerChannel&) = delete;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 180e232..11ffc3f 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -15,6 +15,7 @@
  */
 #include "impl/vr_hwc.h"
 
+#include "android-base/stringprintf.h"
 #include <cutils/properties.h>
 #include <private/dvr/display_client.h>
 #include <ui/Fence.h>
@@ -26,6 +27,7 @@
 using namespace android::hardware::graphics::common::V1_0;
 using namespace android::hardware::graphics::composer::V2_1;
 
+using android::base::StringPrintf;
 using android::hardware::hidl_handle;
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
@@ -225,6 +227,20 @@
     memcpy(color_transform_, matrix, sizeof(color_transform_));
 }
 
+void HwcDisplay::dumpDebugInfo(std::string* result) const {
+  if (!result) {
+    return;
+  }
+  *result += StringPrintf("HwcDisplay: width: %d, height: %d, layers size: %zu, colormode: %d\
+      , config: %d\n", width_, height_, layers_.size(), color_mode_, active_config_);
+  *result += StringPrintf("HwcDisplay buffer metadata: width: %d, height: %d, stride: %d,\
+      layerCount: %d, pixelFormat: %d\n", buffer_metadata_.width, buffer_metadata_.height,
+      buffer_metadata_.stride, buffer_metadata_.layerCount, buffer_metadata_.format);
+  for (const auto& layer : layers_) {
+    layer.dumpDebugInfo(result);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // VrHwcClient
 
@@ -831,7 +847,19 @@
 }
 
 Return<void> VrHwc::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
-  hidl_cb(hidl_string());
+  std::string result;
+
+  {
+    std::lock_guard<std::mutex> guard(mutex_);
+    result = "\nVrHwc states:\n";
+    for (const auto& pair : displays_) {
+      result += StringPrintf("Display id: %lu\n", (unsigned long)pair.first);
+      pair.second->dumpDebugInfo(&result);
+    }
+    result += "\n";
+  }
+
+  hidl_cb(hidl_string(result));
   return Void();
 }
 
@@ -840,7 +868,7 @@
 
   Error status = Error::NONE;
   sp<VrComposerClient> client;
-  if (client_ == nullptr) {
+  if (!client_.promote().get()) {
     client = new VrComposerClient(*this);
   } else {
     ALOGE("Already have a client");
@@ -881,5 +909,22 @@
   return iter == displays_.end() ? nullptr : iter->second.get();
 }
 
+void HwcLayer::dumpDebugInfo(std::string* result) const {
+  if (!result) {
+    return;
+  }
+  *result += StringPrintf("Layer: composition_type: %d, type: %d, app_id: %d, z_order: %d,\
+      cursor_x: %d, cursor_y: %d, color(rgba): (%d,%d,%d,%d), dataspace: %d, transform: %d,\
+      display_frame(LTRB): (%d,%d,%d,%d), crop(LTRB): (%.1f,%.1f,%.1f,%.1f), blend_mode: %d\n",
+      composition_type, info.type, info.app_id, info.z_order, info.cursor_x, info.cursor_y,
+      info.color.r, info.color.g, info.color.b, info.color.a, info.dataspace, info.transform,
+      info.display_frame.left, info.display_frame.top, info.display_frame.right,
+      info.display_frame.bottom, info.crop.left, info.crop.top, info.crop.right,
+      info.crop.bottom, info.blend_mode);
+  *result += StringPrintf("Layer buffer metadata: width: %d, height: %d, stride: %d, layerCount: %d\
+      , pixelFormat: %d\n", buffer_metadata.width, buffer_metadata.height, buffer_metadata.stride,
+      buffer_metadata.layerCount, buffer_metadata.format);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 1c308f2..d5d5f55 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -116,6 +116,8 @@
     info.id = new_id;
   }
 
+  void dumpDebugInfo(std::string* result) const;
+
   Composition composition_type;
   ComposerView::ComposerLayer info;
   IVrComposerClient::BufferMetadata buffer_metadata;
@@ -163,6 +165,8 @@
   int32_t color_transform_hint() const { return color_transform_hint_; }
   void SetColorTransform(const float* matrix, int32_t hint);
 
+  void dumpDebugInfo(std::string* result) const;
+
  private:
   // The client target buffer and the associated fence.
   sp<GraphicBuffer> buffer_;
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 35c6e59..a49b6dd 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -45,6 +45,12 @@
     sdk_version: "24",
 }
 
+llndk_library {
+    name: "libvulkan",
+    symbol_file: "libvulkan/libvulkan.map.txt",
+    export_include_dirs: ["include"],
+}
+
 subdirs = [
     "nulldrv",
     "libvulkan",
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index dec39e0..741fbb8 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -500,13 +500,36 @@
                 // both we and HAL can take part in
                 hook_extensions_.set(ext_bit);
                 break;
-            case ProcHook::EXTENSION_UNKNOWN:
             case ProcHook::KHR_get_physical_device_properties2:
-                // HAL's extensions
+            case ProcHook::EXTENSION_UNKNOWN:
+                // Extensions we don't need to do anything about at this level
                 break;
-            default:
-                ALOGW("Ignored invalid instance extension %s", name);
+
+            case ProcHook::KHR_incremental_present:
+            case ProcHook::KHR_shared_presentable_image:
+            case ProcHook::KHR_swapchain:
+            case ProcHook::EXT_hdr_metadata:
+            case ProcHook::ANDROID_external_memory_android_hardware_buffer:
+            case ProcHook::ANDROID_native_buffer:
+            case ProcHook::GOOGLE_display_timing:
+            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_COUNT:
+                // Device and meta extensions. If we ever get here it's a bug in
+                // our code. But enumerating them lets us avoid having a default
+                // case, and default hides other bugs.
+                ALOGE(
+                    "CreateInfoWrapper::FilterExtension: invalid instance "
+                    "extension '%s'. FIX ME",
+                    name);
                 return;
+
+            // Don't use a default case. Without it, -Wswitch will tell us
+            // at compile time if someone adds a new ProcHook extension but
+            // doesn't handle it above. That's a real bug that has
+            // not-immediately-obvious effects.
+            //
+            // default:
+            //     break;
         }
     } else {
         switch (ext_bit) {
@@ -524,12 +547,36 @@
             case ProcHook::EXT_hdr_metadata:
                 hook_extensions_.set(ext_bit);
                 break;
+            case ProcHook::ANDROID_external_memory_android_hardware_buffer:
             case ProcHook::EXTENSION_UNKNOWN:
-                // HAL's extensions
+                // Extensions we don't need to do anything about at this level
                 break;
-            default:
-                ALOGW("Ignored invalid device extension %s", name);
+
+            case ProcHook::KHR_android_surface:
+            case ProcHook::KHR_get_physical_device_properties2:
+            case ProcHook::KHR_get_surface_capabilities2:
+            case ProcHook::KHR_surface:
+            case ProcHook::EXT_debug_report:
+            case ProcHook::EXT_swapchain_colorspace:
+            case ProcHook::ANDROID_native_buffer:
+            case ProcHook::EXTENSION_CORE:
+            case ProcHook::EXTENSION_COUNT:
+                // Instance and meta extensions. If we ever get here it's a bug
+                // in our code. But enumerating them lets us avoid having a
+                // default case, and default hides other bugs.
+                ALOGE(
+                    "CreateInfoWrapper::FilterExtension: invalid device "
+                    "extension '%s'. FIX ME",
+                    name);
                 return;
+
+            // Don't use a default case. Without it, -Wswitch will tell us
+            // at compile time if someone adds a new ProcHook extension but
+            // doesn't handle it above. That's a real bug that has
+            // not-immediately-obvious effects.
+            //
+            // default:
+            //     break;
         }
     }