Merge "Compute crop using all ancestors, not just immediate parent"
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 014c995..40dbbf5 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -61,7 +61,8 @@
 public:
     bool mActive = true;
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         String8 path8(path);
         char cwd[256];
         getcwd(cwd, 256);
@@ -71,7 +72,26 @@
             aerr << "Open attempt after active for: " << fullPath << endl;
             return -EPERM;
         }
-        int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
+        int flags = 0;
+        bool checkRead = false;
+        bool checkWrite = false;
+        if (mode == String16("w")) {
+            flags = O_WRONLY|O_CREAT|O_TRUNC;
+            checkWrite = true;
+        } else if (mode == String16("w+")) {
+            flags = O_RDWR|O_CREAT|O_TRUNC;
+            checkRead = checkWrite = true;
+        } else if (mode == String16("r")) {
+            flags = O_RDONLY;
+            checkRead = true;
+        } else if (mode == String16("r+")) {
+            flags = O_RDWR;
+            checkRead = checkWrite = true;
+        } else {
+            aerr << "Invalid mode requested: " << mode.string() << endl;
+            return -EINVAL;
+        }
+        int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
         if (fd < 0) {
             return fd;
         }
@@ -80,14 +100,27 @@
             security_context_t tmp = NULL;
             int ret = getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
-            int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                    "file", "write", NULL);
-            if (accessGranted != 0) {
-                close(fd);
-                aerr << "System server has no access to file context " << context.get()
-                        << " (from path " << fullPath.string() << ", context "
-                        << seLinuxContext8.string() << ")" << endl;
-                return -EPERM;
+            if (checkWrite) {
+                int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                        "file", "write", NULL);
+                if (accessGranted != 0) {
+                    close(fd);
+                    aerr << "System server has no access to write file context " << context.get()
+                            << " (from path " << fullPath.string() << ", context "
+                            << seLinuxContext8.string() << ")" << endl;
+                    return -EPERM;
+                }
+            }
+            if (checkRead) {
+                int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                        "file", "read", NULL);
+                if (accessGranted != 0) {
+                    close(fd);
+                    aerr << "System server has no access to read file context " << context.get()
+                            << " (from path " << fullPath.string() << ", context "
+                            << seLinuxContext8.string() << ")" << endl;
+                    return -EPERM;
+                }
             }
         }
         return fd;
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index 5149b7f..83e30a2 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -176,7 +176,6 @@
             }
         }
     }
-    close(fd);
 
     if (!newline) dprintf(out_fd, "\n");
     if (!title.empty()) dprintf(out_fd, "\n");
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index ea7109b..ede4254 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -30,6 +30,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <log/log.h>
 
 #include "DumpstateInternal.h"
@@ -182,8 +183,8 @@
 }
 
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
-    int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-    if (fd < 0) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+    if (fd.get() < 0) {
         int err = errno;
         if (title.empty()) {
             dprintf(out_fd, "*** Error dumping %s: %s\n", path.c_str(), strerror(err));
@@ -194,7 +195,7 @@
         fsync(out_fd);
         return -1;
     }
-    return DumpFileFromFdToFd(title, path, fd, out_fd, PropertiesHelper::IsDryRun());
+    return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
 }
 
 int RunCommandToFd(int fd, const std::string& title, const std::vector<std::string>& full_command,
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b1a03fa..380921d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -207,20 +207,36 @@
         const std::string& name = it->name;
         const int fd = it->fd;
         dumped = true;
+
+        // Seek to the beginning of the file before dumping any data. A given
+        // DumpData entry might be dumped multiple times in the report.
+        //
+        // For example, the most recent ANR entry is dumped to the body of the
+        // main entry and it also shows up as a separate entry in the bugreport
+        // ZIP file.
+        if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
+            MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
+                   strerror(errno));
+        }
+
         if (ds.IsZipping() && add_to_zip) {
             if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
-                MYLOGE("Unable to add %s %s to zip file\n", name.c_str(), type_name);
+                MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
             }
         } else {
             dump_file_from_fd(type_name, name.c_str(), fd);
         }
-
-        close(fd);
     }
 
     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];
@@ -887,9 +903,9 @@
     MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
            dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
 
-    int fd = TEMP_FAILURE_RETRY(
-        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
-    if (fd < 0) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+    if (fd.get() < 0) {
         printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
     } else {
         if (add_to_zip) {
@@ -901,7 +917,7 @@
         } else {
             MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
                    anr_traces_file.c_str());
-            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd);
+            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
         }
     }
 }
@@ -934,12 +950,12 @@
         AddDumps(anr_data->begin(), anr_data->begin() + 1,
                  "VM TRACES AT LAST ANR", add_to_zip);
 
-        if (anr_data->size() > 1) {
-            // NOTE: Historical ANRs are always added as separate entries in the
-            // bugreport zip file.
-            AddDumps(anr_data->begin() + 1, anr_data->end(),
-                     "HISTORICAL ANR", true /* 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(),
+                 "HISTORICAL ANR", true /* add_to_zip */);
     } else {
         printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
     }
@@ -1613,6 +1629,7 @@
             do_fb = 0;
         } else if (ds.extra_options_ == "bugreportwear") {
             ds.update_progress_ = true;
+            do_zip_file = 1;
         } else if (ds.extra_options_ == "bugreporttelephony") {
             telephony_only = true;
         } else {
@@ -2033,5 +2050,8 @@
         close(ds.control_socket_fd_);
     }
 
+    CloseDumpFds(tombstone_data.get());
+    CloseDumpFds(anr_data.get());
+
     return 0;
 }
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index c2c9071..6ff0dae 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -632,7 +632,7 @@
     struct dirent *d;
     char *newpath = NULL;
     const char *slash = "/";
-    int fd, retval = 0;
+    int retval = 0;
 
     if (!title.empty()) {
         printf("------ %s (%s) ------\n", title.c_str(), dir);
@@ -674,13 +674,13 @@
             }
             continue;
         }
-        fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
-        if (fd < 0) {
-            retval = fd;
+        android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+        if (fd.get() < 0) {
+            retval = -1;
             printf("*** %s: %s\n", newpath, strerror(errno));
             continue;
         }
-        (*dump_from_fd)(NULL, newpath, fd);
+        (*dump_from_fd)(NULL, newpath, fd.get());
     }
     closedir(dirp);
     if (!title.empty()) {
@@ -699,11 +699,9 @@
     int flags = fcntl(fd, F_GETFL);
     if (flags == -1) {
         printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
-        close(fd);
         return -1;
     } else if (!(flags & O_NONBLOCK)) {
         printf("*** %s: fd must have O_NONBLOCK set.\n", path);
-        close(fd);
         return -1;
     }
     return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 239a2d5..c36ab08 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -62,6 +62,8 @@
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
             "         -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
+            "         --proto: filter services that support dumping data in proto format. Dumps"
+            "               will be in proto format.\n"
             "         --priority LEVEL: filter services based on specified priority\n"
             "               LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
             "         --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
@@ -77,17 +79,17 @@
     return false;
 }
 
-static bool ConvertPriorityTypeToBitmask(String16& type, int& bitmask) {
-    if (type == PRIORITY_ARG_CRITICAL) {
-        bitmask = IServiceManager::DUMP_PRIORITY_CRITICAL;
+static bool ConvertPriorityTypeToBitmask(const String16& type, int& bitmask) {
+    if (type == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+        bitmask = IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL;
         return true;
     }
-    if (type == PRIORITY_ARG_HIGH) {
-        bitmask = IServiceManager::DUMP_PRIORITY_HIGH;
+    if (type == PriorityDumper::PRIORITY_ARG_HIGH) {
+        bitmask = IServiceManager::DUMP_FLAG_PRIORITY_HIGH;
         return true;
     }
-    if (type == PRIORITY_ARG_NORMAL) {
-        bitmask = IServiceManager::DUMP_PRIORITY_NORMAL;
+    if (type == PriorityDumper::PRIORITY_ARG_NORMAL) {
+        bitmask = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL;
         return true;
     }
     return false;
@@ -98,11 +100,14 @@
     Vector<String16> args;
     String16 priorityType;
     Vector<String16> skippedServices;
+    Vector<String16> protoServices;
     bool showListOnly = false;
     bool skipServices = false;
+    bool filterByProto = false;
     int timeoutArg = 10;
-    int dumpPriority = IServiceManager::DUMP_PRIORITY_ALL;
+    int dumpPriorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
     static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+                                          {"proto", no_argument, 0, 0},
                                           {"skip", no_argument, 0, 0},
                                           {"help", no_argument, 0, 0},
                                           {0, 0, 0, 0}};
@@ -124,12 +129,14 @@
         case 0:
             if (!strcmp(longOptions[optionIndex].name, "skip")) {
                 skipServices = true;
+            } else if (!strcmp(longOptions[optionIndex].name, "proto")) {
+                filterByProto = true;
             } else if (!strcmp(longOptions[optionIndex].name, "help")) {
                 usage();
                 return 0;
             } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
                 priorityType = String16(String8(optarg));
-                if (!ConvertPriorityTypeToBitmask(priorityType, dumpPriority)) {
+                if (!ConvertPriorityTypeToBitmask(priorityType, dumpPriorityFlags)) {
                     fprintf(stderr, "\n");
                     usage();
                     return -1;
@@ -179,10 +186,19 @@
 
     if (services.empty() || showListOnly) {
         // gets all services
-        services = sm_->listServices(dumpPriority);
+        services = sm_->listServices(dumpPriorityFlags);
         services.sort(sort_func);
-        if (dumpPriority != IServiceManager::DUMP_PRIORITY_ALL) {
-            args.insertAt(String16(PRIORITY_ARG), 0);
+        if (filterByProto) {
+            protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
+            protoServices.sort(sort_func);
+            Vector<String16> intersection;
+            std::set_intersection(services.begin(), services.end(), protoServices.begin(),
+                                  protoServices.end(), std::back_inserter(intersection));
+            services = std::move(intersection);
+            args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
+        }
+        if (dumpPriorityFlags != IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
+            args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
             args.insertAt(priorityType, 1);
         } else {
             args.add(String16("-a"));
@@ -230,7 +246,7 @@
             if (N > 1) {
                 aout << "------------------------------------------------------------"
                         "-------------------" << endl;
-                if (dumpPriority == IServiceManager::DUMP_PRIORITY_ALL) {
+                if (dumpPriorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
                     aout << "DUMP OF SERVICE " << service_name << ":" << endl;
                 } else {
                     aout << "DUMP OF SERVICE " << priorityType << " " << service_name << ":" << endl;
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 39fcb80..e182b9d 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -15,6 +15,7 @@
     static_libs: [
         "libdumpsys",
         "libgmock",
+        "libserviceutils",
     ],
 
     clang: true,
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 9fe4572..18a4da9 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 
 #include <android-base/file.h>
+#include <serviceutils/PriorityDumper.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
@@ -131,16 +132,16 @@
         for (auto& service : services) {
             services16.add(String16(service.c_str()));
         }
-        EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_PRIORITY_ALL))
+        EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL))
             .WillRepeatedly(Return(services16));
     }
 
-    void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpPriority) {
+    void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpFlags) {
         Vector<String16> services16;
         for (auto& service : services) {
             services16.add(String16(service.c_str()));
         }
-        EXPECT_CALL(sm_, listServices(dumpPriority)).WillRepeatedly(Return(services16));
+        EXPECT_CALL(sm_, listServices(dumpFlags)).WillRepeatedly(Return(services16));
     }
 
     sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
@@ -210,6 +211,13 @@
         EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
     }
 
+    void AssertDumpedWithPriority(const std::string& service, const std::string& dump,
+                                  const char16_t* priorityType) {
+        std::string priority = String8(priorityType).c_str();
+        EXPECT_THAT(stdout_,
+                    HasSubstr("DUMP OF SERVICE " + priority + " " + service + ":\n" + dump));
+    }
+
     void AssertNotDumped(const std::string& dump) {
         EXPECT_THAT(stdout_, Not(HasSubstr(dump)));
     }
@@ -250,7 +258,7 @@
 
 // Tests 'dumpsys -l --priority HIGH'
 TEST_F(DumpsysTest, ListAllServicesWithPriority) {
-    ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_PRIORITY_HIGH);
+    ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
     ExpectCheckService("Locksmith");
     ExpectCheckService("Valet");
 
@@ -261,13 +269,26 @@
 
 // Tests 'dumpsys -l --priority HIGH' with and empty list
 TEST_F(DumpsysTest, ListEmptyServicesWithPriority) {
-    ExpectListServicesWithPriority({}, IServiceManager::DUMP_PRIORITY_HIGH);
+    ExpectListServicesWithPriority({}, IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
 
     CallMain({"-l", "--priority", "HIGH"});
 
     AssertRunningServices({});
 }
 
+// Tests 'dumpsys -l --proto'
+TEST_F(DumpsysTest, ListAllServicesWithProto) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet", "Car"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+    ExpectListServicesWithPriority({"Valet", "Car"}, IServiceManager::DUMP_FLAG_PROTO);
+    ExpectCheckService("Car");
+    ExpectCheckService("Valet");
+
+    CallMain({"-l", "--proto"});
+
+    AssertRunningServices({"Car", "Valet"});
+}
+
 // Tests 'dumpsys service_name' on a service is running
 TEST_F(DumpsysTest, DumpRunningService) {
     ExpectDump("Valet", "Here's your car");
@@ -336,7 +357,7 @@
 // Tests 'dumpsys --skip skipped3 skipped5 --priority CRITICAL', which should skip these services
 TEST_F(DumpsysTest, DumpWithSkipAndPriority) {
     ExpectListServicesWithPriority({"running1", "stopped2", "skipped3", "running4", "skipped5"},
-                                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+                                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
     ExpectDump("running1", "dump1");
     ExpectCheckService("stopped2", false);
     ExpectDump("skipped3", "dump3");
@@ -346,8 +367,8 @@
     CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"});
 
     AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
-    AssertDumped("running1", "dump1");
-    AssertDumped("running4", "dump4");
+    AssertDumpedWithPriority("running1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+    AssertDumpedWithPriority("running4", "dump4", PriorityDumper::PRIORITY_ARG_CRITICAL);
     AssertStopped("stopped2");
     AssertNotDumped("dump3");
     AssertNotDumped("dump5");
@@ -356,41 +377,74 @@
 // Tests 'dumpsys --priority CRITICAL'
 TEST_F(DumpsysTest, DumpWithPriorityCritical) {
     ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"},
-                                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+                                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
     ExpectDump("runningcritical1", "dump1");
     ExpectDump("runningcritical2", "dump2");
 
     CallMain({"--priority", "CRITICAL"});
 
     AssertRunningServices({"runningcritical1", "runningcritical2"});
-    AssertDumped("runningcritical1", "dump1");
-    AssertDumped("runningcritical2", "dump2");
+    AssertDumpedWithPriority("runningcritical1", "dump1", PriorityDumper::PRIORITY_ARG_CRITICAL);
+    AssertDumpedWithPriority("runningcritical2", "dump2", PriorityDumper::PRIORITY_ARG_CRITICAL);
 }
 
 // Tests 'dumpsys --priority HIGH'
 TEST_F(DumpsysTest, DumpWithPriorityHigh) {
     ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
-                                   IServiceManager::DUMP_PRIORITY_HIGH);
+                                   IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
     ExpectDump("runninghigh1", "dump1");
     ExpectDump("runninghigh2", "dump2");
 
     CallMain({"--priority", "HIGH"});
 
     AssertRunningServices({"runninghigh1", "runninghigh2"});
-    AssertDumped("runninghigh1", "dump1");
-    AssertDumped("runninghigh2", "dump2");
+    AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+    AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
 }
 
 // Tests 'dumpsys --priority NORMAL'
 TEST_F(DumpsysTest, DumpWithPriorityNormal) {
     ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"},
-                                   IServiceManager::DUMP_PRIORITY_NORMAL);
+                                   IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
     ExpectDump("runningnormal1", "dump1");
     ExpectDump("runningnormal2", "dump2");
 
     CallMain({"--priority", "NORMAL"});
 
     AssertRunningServices({"runningnormal1", "runningnormal2"});
-    AssertDumped("runningnormal1", "dump1");
-    AssertDumped("runningnormal2", "dump2");
+    AssertDumpedWithPriority("runningnormal1", "dump1", PriorityDumper::PRIORITY_ARG_NORMAL);
+    AssertDumpedWithPriority("runningnormal2", "dump2", PriorityDumper::PRIORITY_ARG_NORMAL);
+}
+
+// Tests 'dumpsys --proto'
+TEST_F(DumpsysTest, DumpWithProto) {
+    ExpectListServicesWithPriority({"run8", "run1", "run2", "run5"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+    ExpectListServicesWithPriority({"run3", "run2", "run4", "run8"},
+                                   IServiceManager::DUMP_FLAG_PROTO);
+    ExpectDump("run2", "dump1");
+    ExpectDump("run8", "dump2");
+
+    CallMain({"--proto"});
+
+    AssertRunningServices({"run2", "run8"});
+    AssertDumped("run2", "dump1");
+    AssertDumped("run8", "dump2");
+}
+
+// Tests 'dumpsys --priority HIGH --proto'
+TEST_F(DumpsysTest, DumpWithPriorityHighAndProto) {
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+                                   IServiceManager::DUMP_FLAG_PRIORITY_HIGH);
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2", "runninghigh3"},
+                                   IServiceManager::DUMP_FLAG_PROTO);
+
+    ExpectDump("runninghigh1", "dump1");
+    ExpectDump("runninghigh2", "dump2");
+
+    CallMain({"--priority", "HIGH", "--proto"});
+
+    AssertRunningServices({"runninghigh1", "runninghigh2"});
+    AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
+    AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 4bb8ebe..6ce04a2 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -73,6 +73,10 @@
     return android::base::GetProperty("persist.sys.dalvik.vm.lib.2", "") == "libartd.so";
 }
 
+static bool is_debuggable_build() {
+    return android::base::GetBoolProperty("ro.debuggable", false);
+}
+
 static bool clear_profile(const std::string& profile) {
     unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
     if (ufd.get() < 0) {
@@ -197,7 +201,8 @@
 static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
-        bool debuggable, bool post_bootcomplete, int profile_fd, const char* class_loader_context) {
+        bool debuggable, bool post_bootcomplete, bool try_debug_for_background, int profile_fd,
+        const char* class_loader_context) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -274,7 +279,12 @@
     }
 
     // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-    const char* dex2oat_bin = is_debug_runtime() ? "/system/bin/dex2oatd" : "/system/bin/dex2oat";
+    const char* dex2oat_bin = "/system/bin/dex2oat";
+    static const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+    if (is_debug_runtime() || (try_debug_for_background && is_debuggable_build())) {
+        DCHECK(access(kDex2oatDebugPath, X_OK) == 0);
+        dex2oat_bin = kDex2oatDebugPath;
+    }
 
     static const char* RUNTIME_ARG = "--runtime-arg";
 
@@ -1407,7 +1417,7 @@
         argv[i++] = downgrade_flag;
     }
     if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context;
+        argv[i++] = class_loader_context_arg.c_str();
     }
     argv[i] = NULL;
 
@@ -1609,6 +1619,7 @@
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
     bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
     bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+    bool try_debug_for_background = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
 
     // Check if we're dealing with a secondary dex file and if we need to compile it.
     std::string oat_dir_str;
@@ -1704,6 +1715,7 @@
                     compiler_filter,
                     debuggable,
                     boot_complete,
+                    try_debug_for_background,
                     reference_profile_fd.get(),
                     class_loader_context);
         _exit(68);   /* only get here on exec failure */
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 2597c79..b49057d 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -49,6 +49,9 @@
 constexpr int DEXOPT_FORCE          = 1 << 6;
 constexpr int DEXOPT_STORAGE_CE     = 1 << 7;
 constexpr int DEXOPT_STORAGE_DE     = 1 << 8;
+// Tells the compiler that it is invoked from the background service.  This
+// controls whether extra debugging flags can be used (taking more compile time.)
+constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
 
 /* all known values for dexopt flags */
 constexpr int DEXOPT_MASK =
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index c793df3..23b83a6 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -39,11 +39,13 @@
     {
     }
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         Parcel data, reply;
         data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor());
         data.writeString16(path);
         data.writeString16(seLinuxContext);
+        data.writeString16(mode);
         remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0);
         reply.readExceptionCode();
         int fd = reply.readParcelFileDescriptor();
@@ -64,7 +66,8 @@
             CHECK_INTERFACE(IShellCallback, data, reply);
             String16 path(data.readString16());
             String16 seLinuxContext(data.readString16());
-            int fd = openOutputFile(path, seLinuxContext);
+            String16 mode(data.readString16());
+            int fd = openFile(path, seLinuxContext, mode);
             if (reply != NULL) {
                 reply->writeNoException();
                 if (fd >= 0) {
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index 4e69067..4ce82a1 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -35,15 +35,16 @@
 {
 public:
     static status_t publish(bool allowIsolated = false,
-                            int dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL) {
+                            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
         sp<IServiceManager> sm(defaultServiceManager());
         return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
-                              dumpPriority);
+                              dumpFlags);
     }
 
-    static void publishAndJoinThreadPool(bool allowIsolated = false,
-                                         int dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL) {
-        publish(allowIsolated, dumpPriority);
+    static void publishAndJoinThreadPool(
+            bool allowIsolated = false,
+            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
+        publish(allowIsolated, dumpFlags);
         joinThreadPool();
     }
 
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 78b03bd..19e841a 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -34,11 +34,12 @@
     /*
      * Must match values in IServiceManager.java
      */
-    static const int DUMP_PRIORITY_CRITICAL = 1 << 0;
-    static const int DUMP_PRIORITY_HIGH = 1 << 1;
-    static const int DUMP_PRIORITY_NORMAL = 1 << 2;
-    static const int DUMP_PRIORITY_ALL =
-            DUMP_PRIORITY_CRITICAL | DUMP_PRIORITY_HIGH | DUMP_PRIORITY_NORMAL;
+    static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+    static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+    static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
+    static const int DUMP_FLAG_PRIORITY_ALL =
+            DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL;
+    static const int DUMP_FLAG_PROTO = 1 << 3;
 
     /**
      * Retrieve an existing service, blocking for a few seconds
@@ -56,12 +57,12 @@
      */
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                 bool allowIsolated = false,
-                                int dumpsysPriority = DUMP_PRIORITY_NORMAL) = 0;
+                                int dumpsysFlags = DUMP_FLAG_PRIORITY_NORMAL) = 0;
 
     /**
      * Return list of all existing services.
      */
-    virtual Vector<String16> listServices(int dumpsysPriority = DUMP_PRIORITY_ALL) = 0;
+    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
 
     enum {
         GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index fda9ee6..b47e995 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -29,7 +29,8 @@
 public:
     DECLARE_META_INTERFACE(ShellCallback);
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0;
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) = 0;
 
     enum {
         OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 9677125..973302c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -122,6 +122,18 @@
         return reply.readInt32();
     }
 
+    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+                                   const sp<IGraphicBufferProducer>& producer,
+                                   ISurfaceComposer::Rotation rotation) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(layerHandleBinder);
+        data.writeStrongBinder(IInterface::asBinder(producer));
+        data.writeInt32(static_cast<int32_t>(rotation));
+        remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const
     {
@@ -588,6 +600,18 @@
             reply->writeInt32(res);
             return NO_ERROR;
         }
+        case CAPTURE_LAYERS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> layerHandleBinder = data.readStrongBinder();
+            sp<IGraphicBufferProducer> producer =
+                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+            int32_t rotation = data.readInt32();
+
+            status_t res = captureLayers(layerHandleBinder, producer,
+                                         static_cast<ISurfaceComposer::Rotation>(rotation));
+            reply->writeInt32(res);
+            return NO_ERROR;
+        }
         case AUTHENTICATE_SURFACE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IGraphicBufferProducer> bufferProducer =
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index bfc6f28..b5295f2 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -136,5 +136,101 @@
     return NO_ERROR;
 }
 
+void DisplayState::merge(const DisplayState& other) {
+    if (other.what & eSurfaceChanged) {
+        what |= eSurfaceChanged;
+        surface = other.surface;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eDisplayProjectionChanged) {
+        what |= eDisplayProjectionChanged;
+        orientation = other.orientation;
+        viewport = other.viewport;
+        frame = other.frame;
+    }
+    if (other.what & eDisplaySizeChanged) {
+        what |= eDisplaySizeChanged;
+        width = other.width;
+        height = other.height;
+    }
+}
+
+void layer_state_t::merge(const layer_state_t& other) {
+    if (other.what & ePositionChanged) {
+        what |= ePositionChanged;
+        x = other.x;
+        y = other.y;
+    }
+    if (other.what & eLayerChanged) {
+        what |= eLayerChanged;
+        z = other.z;
+    }
+    if (other.what & eSizeChanged) {
+        what |= eSizeChanged;
+        w = other.w;
+        h = other.h;
+    }
+    if (other.what & eAlphaChanged) {
+        what |= eAlphaChanged;
+        alpha = other.alpha;
+    }
+    if (other.what & eMatrixChanged) {
+        what |= eMatrixChanged;
+        matrix = other.matrix;
+    }
+    if (other.what & eTransparentRegionChanged) {
+        what |= eTransparentRegionChanged;
+        transparentRegion = other.transparentRegion;
+    }
+    if (other.what & eFlagsChanged) {
+        what |= eFlagsChanged;
+        flags = other.flags;
+        mask = other.mask;
+    }
+    if (other.what & eLayerStackChanged) {
+        what |= eLayerStackChanged;
+        layerStack = other.layerStack;
+    }
+    if (other.what & eCropChanged) {
+        what |= eCropChanged;
+        crop = other.crop;
+    }
+    if (other.what & eDeferTransaction) {
+        what |= eDeferTransaction;
+        barrierHandle = other.barrierHandle;
+        barrierGbp = other.barrierGbp;
+        frameNumber = other.frameNumber;
+    }
+    if (other.what & eFinalCropChanged) {
+        what |= eFinalCropChanged;
+        finalCrop = other.finalCrop;
+    }
+    if (other.what & eOverrideScalingModeChanged) {
+        what |= eOverrideScalingModeChanged;
+        overrideScalingMode = other.overrideScalingMode;
+    }
+    if (other.what & eGeometryAppliesWithResize) {
+        what |= eGeometryAppliesWithResize;
+    }
+    if (other.what & eReparentChildren) {
+        what |= eReparentChildren;
+        reparentHandle = other.reparentHandle;
+    }
+    if (other.what & eDetachChildren) {
+        what |= eDetachChildren;
+    }
+    if (other.what & eRelativeLayerChanged) {
+        what |= eRelativeLayerChanged;
+        z = other.z;
+        relativeLayerHandle = other.relativeLayerHandle;
+    }
+    if (other.what & eReparent) {
+        what |= eReparent;
+        parentHandleForChild = other.parentHandleForChild;
+    }
+}
 
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 40e319e..2adc273 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -104,6 +104,30 @@
     mComposerStates = other.mComposerStates;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
+    for (auto const& state : other.mComposerStates) {
+        ssize_t index = mComposerStates.indexOf(state);
+        if (index < 0) {
+            mComposerStates.add(state);
+        } else {
+            mComposerStates.editItemAt(static_cast<size_t>(index)).state.merge(state.state);
+        }
+    }
+    other.mComposerStates.clear();
+
+    for (auto const& state : other.mDisplayStates) {
+        ssize_t index = mDisplayStates.indexOf(state);
+        if (index < 0) {
+            mDisplayStates.add(state);
+        } else {
+            mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
+        }
+    }
+    other.mDisplayStates.clear();
+
+    return *this;
+}
+
 status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
     if (mStatus != NO_ERROR) {
         return mStatus;
@@ -731,6 +755,15 @@
     return ret;
 }
 
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
+                                         const sp<IGraphicBufferProducer>& producer,
+                                         uint32_t rotation) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+    return s->captureLayers(layerHandle, producer,
+                            static_cast<ISurfaceComposer::Rotation>(rotation));
+}
+
 ScreenshotClient::ScreenshotClient()
     : mHaveBuffer(false) {
     memset(&mBuffer, 0, sizeof(mBuffer));
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b226742..13e7473 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -174,6 +174,10 @@
             bool useIdentityTransform,
             Rotation rotation = eRotateNone) = 0;
 
+    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
+                                   const sp<IGraphicBufferProducer>& producer,
+                                   Rotation rotation = eRotateNone) = 0;
+
     /* Clears the frame statistics for animations.
      *
      * Requires the ACCESS_SURFACE_FLINGER permission.
@@ -226,6 +230,7 @@
         SET_ACTIVE_CONFIG,
         CONNECT_DISPLAY,
         CAPTURE_SCREEN,
+        CAPTURE_LAYERS,
         CLEAR_ANIMATION_FRAME_STATS,
         GET_ANIMATION_FRAME_STATS,
         SET_POWER_MODE,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index ae6965a..f3fb82f 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -77,6 +77,7 @@
         matrix.dsdy = matrix.dtdx = 0.0f;
     }
 
+    void merge(const layer_state_t& other);
     status_t    write(Parcel& output) const;
     status_t    read(const Parcel& input);
 
@@ -144,6 +145,7 @@
     };
 
     DisplayState();
+    void merge(const DisplayState& other);
 
     uint32_t what;
     sp<IBinder> token;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 00d5936..87fdfae 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -144,7 +144,9 @@
         Transaction(Transaction const& other);
 
         status_t apply(bool synchronous = false);
-
+        // Merge another transaction in to this one, clearing other
+        // as if it had been applied.
+        Transaction& merge(Transaction&& other);
         Transaction& show(const sp<SurfaceControl>& sc);
         Transaction& hide(const sp<SurfaceControl>& sc);
         Transaction& setPosition(const sp<SurfaceControl>& sc,
@@ -175,8 +177,6 @@
                 float alpha);
         Transaction& setMatrix(const sp<SurfaceControl>& sc,
                 float dsdx, float dtdx, float dtdy, float dsdy);
-        Transaction& setOrientation(const sp<SurfaceControl>& sc,
-                const Rect& crop);
         Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
         Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
         Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
@@ -297,6 +297,9 @@
             bool useIdentityTransform,
             uint32_t rotation,
             sp<GraphicBuffer>* outbuffer);
+    static status_t captureLayers(const sp<IBinder>& layerHandle,
+                                  const sp<IGraphicBufferProducer>& producer, uint32_t rotation);
+
 private:
     mutable sp<CpuConsumer> mCpuConsumer;
     mutable sp<IGraphicBufferProducer> mProducer;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 572760e..660680b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -529,6 +529,11 @@
             int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/,
             bool /*useIdentityTransform*/,
             Rotation /*rotation*/) override { return NO_ERROR; }
+    virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
+                                   const sp<IGraphicBufferProducer>& /*producer*/,
+                                   ISurfaceComposer::Rotation /*rotation*/) override {
+        return NO_ERROR;
+    }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
         return NO_ERROR;
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index c4ffb41..5e4df84 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -54,7 +54,7 @@
     tags: ["optional"],
 }
 
-cc_test {
+cc_benchmark {
     srcs: ["buffer_transport_benchmark.cpp"],
     static_libs: static_libraries,
     shared_libs: shared_libraries,
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
index 5b580df..658b496 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
@@ -1,24 +1,24 @@
 #include <android/native_window.h>
-#include <base/logging.h>
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <dvr/dvr_api.h>
 #include <dvr/performance_client_api.h>
-#include <gtest/gtest.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 #include <private/dvr/buffer_hub_queue_producer.h>
 #include <utils/Trace.h>
 
+#include <chrono>
 #include <functional>
-#include <mutex>
+#include <iostream>
 #include <thread>
 #include <vector>
 
 #include <poll.h>
 #include <sys/wait.h>
-#include <unistd.h>  // for pipe
 
 // Use ALWAYS at the tag level. Control is performed manually during command
 // line processing.
@@ -29,6 +29,7 @@
 
 using namespace android;
 using namespace android::dvr;
+using ::benchmark::State;
 
 static const String16 kBinderService = String16("bufferTransport");
 static const uint32_t kBufferWidth = 100;
@@ -38,82 +39,13 @@
 static const uint64_t kBufferUsage =
     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
 static const int kMaxAcquiredImages = 1;
+static const int kQueueDepth = 2;  // We are double buffering for this test.
 static const size_t kMaxQueueCounts = 128;
 
-static int gConcurrency = 1;  // 1 writer at a time
-static int gIterations = 1000;  // 1K times
-static int gSleepIntervalUs = 16 * 1000;  // 16ms
-
 enum BufferTransportServiceCode {
   CREATE_BUFFER_QUEUE = IBinder::FIRST_CALL_TRANSACTION,
 };
 
-// A mininal cross process helper class based on a bidirectional pipe pair. This
-// is used to signal that Binder-based BufferTransportService has finished
-// initialization.
-class Pipe {
- public:
-  static std::tuple<Pipe, Pipe> CreatePipePair() {
-    int a[2] = {-1, -1};
-    int b[2] = {-1, -1};
-
-    pipe(a);
-    pipe(b);
-
-    return std::make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
-  }
-
-  Pipe() = default;
-
-  Pipe(Pipe&& other) {
-    read_fd_ = other.read_fd_;
-    write_fd_ = other.write_fd_;
-    other.read_fd_ = 0;
-    other.write_fd_ = 0;
-  }
-
-  Pipe& operator=(Pipe&& other) {
-    Reset();
-    read_fd_ = other.read_fd_;
-    write_fd_ = other.write_fd_;
-    other.read_fd_ = 0;
-    other.write_fd_ = 0;
-    return *this;
-  }
-
-  ~Pipe() { Reset(); }
-
-  Pipe(const Pipe&) = delete;
-  Pipe& operator=(const Pipe&) = delete;
-  Pipe& operator=(const Pipe&&) = delete;
-
-  bool IsValid() { return read_fd_ > 0 && write_fd_ > 0; }
-
-  void Signal() {
-    bool val = true;
-    int error = write(write_fd_, &val, sizeof(val));
-    ASSERT_GE(error, 0);
-  };
-
-  void Wait() {
-    bool val = false;
-    int error = read(read_fd_, &val, sizeof(val));
-    ASSERT_GE(error, 0);
-  }
-
-  void Reset() {
-    if (read_fd_)
-      close(read_fd_);
-    if (write_fd_)
-      close(write_fd_);
-  }
-
- private:
-  int read_fd_ = -1;
-  int write_fd_ = -1;
-  Pipe(int read_fd, int write_fd) : read_fd_{read_fd}, write_fd_{write_fd} {}
-};
-
 // A binder services that minics a compositor that consumes buffers. It provides
 // one Binder interface to create a new Surface for buffer producer to write
 // into; while itself will carry out no-op buffer consuming by acquiring then
@@ -149,8 +81,6 @@
           buffer_item_consumer_(buffer_item_consumer) {}
 
     void onFrameAvailable(const BufferItem& /*item*/) override {
-      std::unique_lock<std::mutex> autolock(service_->reader_mutex_);
-
       BufferItem buffer;
       status_t ret = 0;
       {
@@ -197,7 +127,6 @@
     sp<FrameListener> frame_listener_;
   };
 
-  std::mutex reader_mutex_;
   std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
 };
 
@@ -225,32 +154,19 @@
  public:
   BinderBufferTransport() {}
 
-  ~BinderBufferTransport() {
-    if (client_pipe_.IsValid()) {
-      client_pipe_.Signal();
-      LOG(INFO) << "Client signals service to shut down.";
-    }
-  }
-
   int Start() override {
-    // Fork a process to run a binder server. The parent process will return
-    // a pipe here, and we use the pipe to signal the binder server to exit.
-    client_pipe_ = CreateBinderServer();
+    sp<IServiceManager> sm = defaultServiceManager();
+    service_ = sm->getService(kBinderService);
+    if (service_ == nullptr) {
+      LOG(ERROR) << "Failed to get the benchmark service.";
+      return -EIO;
+    }
 
-    // Wait until service is ready.
-    LOG(INFO) << "Service is ready for client.";
-    client_pipe_.Wait();
+    LOG(INFO) << "Binder server is ready for client.";
     return 0;
   }
 
   sp<Surface> CreateSurface() override {
-    sp<IServiceManager> sm = defaultServiceManager();
-    service_ = sm->getService(kBinderService);
-    if (service_ == nullptr) {
-      LOG(ERROR) << "Failed to set the benchmark service.";
-      return nullptr;
-    }
-
     Parcel data;
     Parcel reply;
     int error = service_->transact(CREATE_BUFFER_QUEUE, data, &reply);
@@ -283,38 +199,7 @@
   }
 
  private:
-  static Pipe CreateBinderServer() {
-    std::tuple<Pipe, Pipe> pipe_pair = Pipe::CreatePipePair();
-    pid_t pid = fork();
-    if (pid) {
-      // parent, i.e. the client side.
-      ProcessState::self()->startThreadPool();
-      LOG(INFO) << "Binder server pid: " << pid;
-      return std::move(std::get<0>(pipe_pair));
-    } else {
-      // child, i.e. the service side.
-      Pipe service_pipe = std::move(std::get<1>(pipe_pair));
-
-      ProcessState::self()->startThreadPool();
-      sp<IServiceManager> sm = defaultServiceManager();
-      sp<BufferTransportService> service = new BufferTransportService;
-      sm->addService(kBinderService, service, false);
-
-      LOG(INFO) << "Binder Service Running...";
-
-      service_pipe.Signal();
-      service_pipe.Wait();
-
-      LOG(INFO) << "Service Exiting...";
-      exit(EXIT_SUCCESS);
-
-      /* never get here */
-      return {};
-    }
-  }
-
   sp<IBinder> service_;
-  Pipe client_pipe_;
 };
 
 // BufferHub/PDX-based buffer transport.
@@ -378,7 +263,6 @@
         const int num_events = ret;
         for (int i = 0; i < num_events; i++) {
           uint32_t surface_index = events[i].data.u32;
-          // LOG(INFO) << "!!! handle queue events index: " << surface_index;
           buffer_queues_[surface_index]->consumer_queue_->HandleQueueEvents();
         }
       }
@@ -390,8 +274,6 @@
   }
 
   sp<Surface> CreateSurface() override {
-    std::lock_guard<std::mutex> autolock(queue_mutex_);
-
     auto new_queue = std::make_shared<BufferQueueHolder>();
     if (new_queue->producer_ == nullptr) {
       LOG(ERROR) << "Failed to create buffer producer.";
@@ -472,8 +354,6 @@
   std::atomic<bool> stopped_;
   std::thread reader_thread_;
 
-  // Mutex to guard epoll_fd_ and buffer_queues_.
-  std::mutex queue_mutex_;
   EpollFileDescriptor epoll_fd_;
   std::vector<std::shared_ptr<BufferQueueHolder>> buffer_queues_;
 };
@@ -486,124 +366,155 @@
 // Main test suite, which supports two transport backend: 1) BinderBufferQueue,
 // 2) BufferHubQueue. The test case drives the producer end of both transport
 // backend by queuing buffers into the buffer queue by using ANativeWindow API.
-class BufferTransportBenchmark
-    : public ::testing::TestWithParam<TransportType> {
+class BufferTransportBenchmark : public ::benchmark::Fixture {
  public:
-  void SetUp() override {
-    switch (GetParam()) {
-      case kBinderBufferTransport:
-        transport_.reset(new BinderBufferTransport);
-        break;
-      case kBufferHubTransport:
-        transport_.reset(new BufferHubTransport);
-        break;
-      default:
-        FAIL() << "Unknown test case.";
-        break;
+  void SetUp(State& state) override {
+    if (state.thread_index == 0) {
+      const int transport = state.range(0);
+      switch (transport) {
+        case kBinderBufferTransport:
+          transport_.reset(new BinderBufferTransport);
+          break;
+        case kBufferHubTransport:
+          transport_.reset(new BufferHubTransport);
+          break;
+        default:
+          CHECK(false) << "Unknown test case.";
+          break;
+      }
+
+      CHECK(transport_);
+      const int ret = transport_->Start();
+      CHECK_EQ(ret, 0);
+
+      LOG(INFO) << "Transport backend running, transport=" << transport << ".";
+
+      // Create surfaces for each thread.
+      surfaces_.resize(state.threads);
+      for (int i = 0; i < state.threads; i++) {
+        // Common setup every thread needs.
+        surfaces_[i] = transport_->CreateSurface();
+        CHECK(surfaces_[i]);
+
+        LOG(INFO) << "Surface initialized on thread " << i << ".";
+      }
+    }
+  }
+
+  void TearDown(State& state) override {
+    if (state.thread_index == 0) {
+      surfaces_.clear();
+      transport_.reset();
+      LOG(INFO) << "Tear down benchmark.";
     }
   }
 
  protected:
-  void ProduceBuffers(sp<Surface> surface, int iterations, int sleep_usec) {
-    ANativeWindow* window = static_cast<ANativeWindow*>(surface.get());
-    ANativeWindow_Buffer buffer;
-    int32_t error = 0;
+  std::unique_ptr<BufferTransport> transport_;
+  std::vector<sp<Surface>> surfaces_;
+};
 
-    for (int i = 0; i < iterations; i++) {
-      usleep(sleep_usec);
+BENCHMARK_DEFINE_F(BufferTransportBenchmark, Producers)(State& state) {
+  ANativeWindow* window = nullptr;
+  ANativeWindow_Buffer buffer;
+  int32_t error = 0;
+  double total_gain_buffer_us = 0;
+  double total_post_buffer_us = 0;
+  int iterations = 0;
 
-      {
-        ATRACE_NAME("GainBuffer");
+  while (state.KeepRunning()) {
+    if (window == nullptr) {
+      CHECK(surfaces_[state.thread_index]);
+      window = static_cast<ANativeWindow*>(surfaces_[state.thread_index].get());
+
+      // Lock buffers a couple time from the queue, so that we have the buffer
+      // allocated.
+      for (int i = 0; i < kQueueDepth; i++) {
         error = ANativeWindow_lock(window, &buffer,
                                    /*inOutDirtyBounds=*/nullptr);
-      }
-      ASSERT_EQ(error, 0);
-
-      {
-        ATRACE_NAME("PostBuffer");
+        CHECK_EQ(error, 0);
         error = ANativeWindow_unlockAndPost(window);
+        CHECK_EQ(error, 0);
       }
-      ASSERT_EQ(error, 0);
+    }
+
+    {
+      ATRACE_NAME("GainBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_lock(window, &buffer,
+                                 /*inOutDirtyBounds=*/nullptr);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_gain_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    {
+      ATRACE_NAME("PostBuffer");
+      auto t1 = std::chrono::high_resolution_clock::now();
+      error = ANativeWindow_unlockAndPost(window);
+      auto t2 = std::chrono::high_resolution_clock::now();
+      std::chrono::duration<double, std::micro> delta_us = t2 - t1;
+      total_post_buffer_us += delta_us.count();
+    }
+    CHECK_EQ(error, 0);
+
+    iterations++;
+  }
+
+  state.counters["gain_buffer_us"] = ::benchmark::Counter(
+      total_gain_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["post_buffer_us"] = ::benchmark::Counter(
+      total_post_buffer_us / iterations, ::benchmark::Counter::kAvgThreads);
+  state.counters["producer_us"] = ::benchmark::Counter(
+      (total_gain_buffer_us + total_post_buffer_us) / iterations,
+      ::benchmark::Counter::kAvgThreads);
+}
+
+BENCHMARK_REGISTER_F(BufferTransportBenchmark, Producers)
+    ->Unit(::benchmark::kMicrosecond)
+    ->Ranges({{kBinderBufferTransport, kBufferHubTransport}})
+    ->ThreadRange(1, 32);
+
+static void runBinderServer() {
+  ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  ProcessState::self()->startThreadPool();
+
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<BufferTransportService> service = new BufferTransportService;
+  sm->addService(kBinderService, service, false);
+
+  LOG(INFO) << "Binder server running...";
+
+  while (true) {
+    int stat, retval;
+    retval = wait(&stat);
+    if (retval == -1 && errno == ECHILD) {
+      break;
     }
   }
 
-  std::unique_ptr<BufferTransport> transport_;
-};
-
-TEST_P(BufferTransportBenchmark, ContinuousLoad) {
-  ASSERT_NE(transport_, nullptr);
-  const int ret = transport_->Start();
-  ASSERT_EQ(ret, 0);
-
-  LOG(INFO) << "Start Running.";
-
-  std::vector<std::thread> writer_threads;
-  for (int i = 0; i < gConcurrency; i++) {
-    std::thread writer_thread = std::thread([this]() {
-      sp<Surface> surface = transport_->CreateSurface();
-      ASSERT_NE(surface, nullptr);
-
-      ASSERT_NO_FATAL_FAILURE(
-          ProduceBuffers(surface, gIterations, gSleepIntervalUs));
-
-      usleep(1000 * 100);
-    });
-
-    writer_threads.push_back(std::move(writer_thread));
-  }
-
-  for (auto& writer_thread : writer_threads) {
-    writer_thread.join();
-  }
-
-  LOG(INFO) << "All done.";
-};
-
-INSTANTIATE_TEST_CASE_P(BufferTransportBenchmarkInstance,
-                        BufferTransportBenchmark,
-                        ::testing::ValuesIn({kBinderBufferTransport,
-                                             kBufferHubTransport}));
+  LOG(INFO) << "Service Exiting...";
+}
 
 // To run binder-based benchmark, use:
 // adb shell buffer_transport_benchmark \
-//   --gtest_filter="BufferTransportBenchmark.ContinuousLoad/0"
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/0/"
 //
 // To run bufferhub-based benchmark, use:
 // adb shell buffer_transport_benchmark \
-//   --gtest_filter="BufferTransportBenchmark.ContinuousLoad/1"
+//   --benchmark_filter="BufferTransportBenchmark/ContinuousLoad/1/"
 int main(int argc, char** argv) {
   bool tracing_enabled = false;
 
-  // Parse arguments in addition to "--gtest_filter" paramters.
+  // Parse arguments in addition to "--benchmark_filter" paramters.
   for (int i = 1; i < argc; i++) {
     if (std::string(argv[i]) == "--help") {
       std::cout << "Usage: binderThroughputTest [OPTIONS]" << std::endl;
-      std::cout << "\t-c N: Specify number of concurrent writer threads, "
-                   "(default: 1, max: 128)."
-                << std::endl;
-      std::cout << "\t-i N: Specify number of iterations, (default: 1000)."
-                << std::endl;
-      std::cout << "\t-s N: Specify sleep interval in usec, (default: 16000)."
-                << std::endl;
       std::cout << "\t--trace: Enable systrace logging."
                 << std::endl;
       return 0;
     }
-    if (std::string(argv[i]) == "-c") {
-      gConcurrency = atoi(argv[i + 1]);
-      i++;
-      continue;
-    }
-    if (std::string(argv[i]) == "-s") {
-      gSleepIntervalUs = atoi(argv[i + 1]);
-      i++;
-      continue;
-    }
-    if (std::string(argv[i]) == "-i") {
-      gIterations = atoi(argv[i + 1]);
-      i++;
-      continue;
-    }
     if (std::string(argv[i]) == "--trace") {
       tracing_enabled = true;
       continue;
@@ -614,6 +525,15 @@
   atrace_setup();
   atrace_set_tracing_enabled(tracing_enabled);
 
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  pid_t pid = fork();
+  if (pid == 0) {
+    // parent, i.e. the client side.
+    ProcessState::self()->startThreadPool();
+
+    ::benchmark::Initialize(&argc, argv);
+    ::benchmark::RunSpecifiedBenchmarks();
+  } else {
+    LOG(INFO) << "Benchmark process pid: " << pid;
+    runBinderServer();
+  }
 }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index d8152e0..d9bca04 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -40,6 +40,7 @@
     RenderEngine/Texture.cpp \
     RenderEngine/GLES20RenderEngine.cpp \
     LayerProtoHelper.cpp \
+    RenderArea.cpp \
 
 LOCAL_MODULE := libsurfaceflinger
 LOCAL_C_INCLUDES := \
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 6923782..32526dd 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -40,13 +40,12 @@
     : Layer(flinger, client, name, w, h, flags) {
 }
 
-void ColorLayer::onDraw(const sp<const DisplayDevice>& hw,
-        const Region& /* clip */, bool useIdentityTransform) const
-{
+void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
+                        bool useIdentityTransform) const {
     const State& s(getDrawingState());
     if (s.color.a>0) {
         Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
-        computeGeometry(hw, mesh, useIdentityTransform);
+        computeGeometry(renderArea, mesh, useIdentityTransform);
         RenderEngine& engine(mFlinger->getRenderEngine());
         engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
               true /* disableTexture */, s.color);
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index ac3e2a9..cdf3eca 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -34,7 +34,7 @@
     virtual ~ColorLayer() = default;
 
     virtual const char* getTypeId() const { return "ColorLayer"; }
-    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
+    virtual void onDraw(const RenderArea& renderArea, const Region& clip,
             bool useIdentityTransform) const;
     virtual bool isOpaque(const Layer::State&) const { return false; }
     virtual bool isSecure() const         { return false; }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8636e2a..49fef58 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -37,7 +37,9 @@
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
+#include <gui/ISurfaceComposer.h>
 #include <hardware/hwcomposer_defs.h>
+#include "RenderArea.h"
 
 #ifdef USE_HWC2
 #include <memory>
@@ -300,6 +302,35 @@
     bool isSecure = false;
 };
 
+class DisplayRenderArea : public RenderArea {
+public:
+    DisplayRenderArea(const sp<const DisplayDevice> device,
+                      ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
+          : DisplayRenderArea(device, device->getBounds(), device->getHeight(), device->getWidth(),
+                              rotation) {}
+    DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight,
+                      uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+          : RenderArea(reqHeight, reqWidth, rotation), mDevice(device), mSourceCrop(sourceCrop) {}
+
+    const Transform& getTransform() const override { return mDevice->getTransform(); }
+    Rect getBounds() const override { return mDevice->getBounds(); }
+    int getHeight() const override { return mDevice->getHeight(); }
+    int getWidth() const override { return mDevice->getWidth(); }
+    bool isSecure() const override { return mDevice->isSecure(); }
+    bool needsFiltering() const override { return mDevice->needsFiltering(); }
+    Rect getSourceCrop() const override { return mSourceCrop; }
+#ifdef USE_HWC2
+    bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); }
+    android_color_mode_t getActiveColorMode() const override {
+        return mDevice->getActiveColorMode();
+    }
+#endif
+
+private:
+    const sp<const DisplayDevice> mDevice;
+    const Rect mSourceCrop;
+};
+
 }; // namespace android
 
 #endif // ANDROID_DISPLAY_DEVICE_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index dbace32..3e7da38 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1065,17 +1065,16 @@
 // drawing...
 // ---------------------------------------------------------------------------
 
-void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
-    onDraw(hw, clip, false);
+void Layer::draw(const RenderArea& renderArea, const Region& clip) const {
+    onDraw(renderArea, clip, false);
 }
 
-void Layer::draw(const sp<const DisplayDevice>& hw,
-        bool useIdentityTransform) const {
-    onDraw(hw, Region(hw->bounds()), useIdentityTransform);
+void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const {
+    onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
 }
 
-void Layer::draw(const sp<const DisplayDevice>& hw) const {
-    onDraw(hw, Region(hw->bounds()), false);
+void Layer::draw(const RenderArea& renderArea) const {
+    onDraw(renderArea, Region(renderArea.getBounds()), false);
 }
 
 static constexpr mat4 inverseOrientation(uint32_t transform) {
@@ -1099,7 +1098,7 @@
 /*
  * onDraw will draw the current layer onto the presentable buffer
  */
-void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
+void Layer::onDraw(const RenderArea& renderArea, const Region& clip,
         bool useIdentityTransform) const
 {
     ATRACE_CALL();
@@ -1121,12 +1120,12 @@
                 finished = true;
                 return;
             }
-            under.orSelf( hw->getTransform().transform(layer->visibleRegion) );
+            under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
         });
         // if not everything below us is covered, we plug the holes!
         Region holes(clip.subtract(under));
         if (!holes.isEmpty()) {
-            clearWithOpenGL(hw, 0, 0, 0, 1);
+            clearWithOpenGL(renderArea, 0, 0, 0, 1);
         }
         return;
     }
@@ -1140,13 +1139,13 @@
         // is probably going to have something visibly wrong.
     }
 
-    bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure());
+    bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
 
     RenderEngine& engine(mFlinger->getRenderEngine());
 
     if (!blackOutLayer) {
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize();
+        const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -1192,31 +1191,29 @@
     } else {
         engine.setupLayerBlackedOut();
     }
-    drawWithOpenGL(hw, useIdentityTransform);
+    drawWithOpenGL(renderArea, useIdentityTransform);
     engine.disableTexturing();
 }
 
 
-void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw,
+void Layer::clearWithOpenGL(const RenderArea& renderArea,
         float red, float green, float blue,
         float alpha) const
 {
     RenderEngine& engine(mFlinger->getRenderEngine());
-    computeGeometry(hw, mMesh, false);
+    computeGeometry(renderArea, mMesh, false);
     engine.setupFillWithColor(red, green, blue, alpha);
     engine.drawMesh(mMesh);
 }
 
-void Layer::clearWithOpenGL(
-        const sp<const DisplayDevice>& hw) const {
-    clearWithOpenGL(hw, 0,0,0,0);
+void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
+    clearWithOpenGL(renderArea, 0,0,0,0);
 }
 
-void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw,
-        bool useIdentityTransform) const {
+void Layer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
     const State& s(getDrawingState());
 
-    computeGeometry(hw, mMesh, useIdentityTransform);
+    computeGeometry(renderArea, mMesh, useIdentityTransform);
 
     /*
      * NOTE: the way we compute the texture coordinates here produces
@@ -1442,12 +1439,11 @@
     }
 }
 
-void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
-        bool useIdentityTransform) const
-{
+void Layer::computeGeometry(const RenderArea& renderArea, Mesh& mesh,
+                            bool useIdentityTransform) const {
     const Layer::State& s(getDrawingState());
-    const Transform hwTransform(hw->getTransform());
-    const uint32_t hw_h = hw->getHeight();
+    const Transform renderAreaTransform(renderArea.getTransform());
+    const uint32_t height = renderArea.getHeight();
     Rect win = computeBounds();
 
     vec2 lt = vec2(win.left, win.top);
@@ -1471,12 +1467,12 @@
     }
 
     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    position[0] = hwTransform.transform(lt);
-    position[1] = hwTransform.transform(lb);
-    position[2] = hwTransform.transform(rb);
-    position[3] = hwTransform.transform(rt);
+    position[0] = renderAreaTransform.transform(lt);
+    position[1] = renderAreaTransform.transform(lb);
+    position[2] = renderAreaTransform.transform(rb);
+    position[3] = renderAreaTransform.transform(rt);
     for (size_t i=0 ; i<4 ; i++) {
-        position[i].y = hw_h - position[i].y;
+        position[i].y = height - position[i].y;
     }
 }
 
@@ -1514,8 +1510,8 @@
     return !mCurrentCrop.isEmpty();
 }
 
-bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const {
-    return mNeedsFiltering || hw->needsFiltering();
+bool Layer::needsFiltering(const RenderArea& renderArea) const {
+    return mNeedsFiltering || renderArea.needsFiltering();
 }
 
 void Layer::setVisibleRegion(const Region& visibleRegion) {
@@ -2775,6 +2771,29 @@
     }
 }
 
+/**
+ * Traverse only children in z order, ignoring relative layers.
+ */
+void Layer::traverseChildrenInZOrder(LayerVector::StateSet stateSet,
+                                     const LayerVector::Visitor& visitor) {
+    const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
+    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
+
+    size_t i = 0;
+    for (; i < children.size(); i++) {
+        const auto& relative = children[i];
+        if (relative->getZ() >= 0) {
+            break;
+        }
+        relative->traverseChildrenInZOrder(stateSet, visitor);
+    }
+    visitor(this);
+    for (; i < children.size(); i++) {
+        const auto& relative = children[i];
+        relative->traverseChildrenInZOrder(stateSet, visitor);
+    }
+}
+
 Transform Layer::getTransform() const {
     Transform t;
     const auto& p = mDrawingParent.promote();
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 06c4863..d75e175 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -50,6 +50,7 @@
 #include "RenderEngine/Mesh.h"
 #include "RenderEngine/Texture.h"
 #include <layerproto/LayerProtoHeader.h>
+#include "RenderArea.h"
 
 #include <math/vec4.h>
 
@@ -255,8 +256,7 @@
         return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
     }
 
-    void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
-            bool useIdentityTransform) const;
+    void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
     Rect computeBounds(const Region& activeTransparentRegion) const;
     Rect computeBounds() const;
 
@@ -312,7 +312,7 @@
     /*
      * onDraw - draws the surface.
      */
-    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
+    virtual void onDraw(const RenderArea& renderArea, const Region& clip,
             bool useIdentityTransform) const;
 
 public:
@@ -379,9 +379,9 @@
      * draw - performs some global clipping optimizations
      * and calls onDraw().
      */
-    void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
-    void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const;
-    void draw(const sp<const DisplayDevice>& hw) const;
+    void draw(const RenderArea& renderArea, const Region& clip) const;
+    void draw(const RenderArea& renderArea, bool useIdentityTransform) const;
+    void draw(const RenderArea& renderArea) const;
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
@@ -472,7 +472,7 @@
 #endif
     // -----------------------------------------------------------------------
 
-    void clearWithOpenGL(const sp<const DisplayDevice>& hw) const;
+    void clearWithOpenGL(const RenderArea& renderArea) const;
     void setFiltering(bool filtering);
     bool getFiltering() const;
 
@@ -516,6 +516,9 @@
                                  const LayerVector::Visitor& visitor);
     void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
 
+    void traverseChildrenInZOrder(LayerVector::StateSet stateSet,
+                                  const LayerVector::Visitor& visitor);
+
     size_t getChildrenCount() const;
     void addChild(const sp<Layer>& layer);
     // Returns index if removed, or negative value otherwise
@@ -569,7 +572,7 @@
     void commitTransaction(const State& stateToCommit);
 
     // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const sp<const DisplayDevice>& hw) const;
+    bool needsFiltering(const RenderArea& renderArea) const;
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
@@ -582,9 +585,9 @@
     static bool getOpacityForFormat(uint32_t format);
 
     // drawing
-    void clearWithOpenGL(const sp<const DisplayDevice>& hw,
+    void clearWithOpenGL(const RenderArea& renderArea,
             float r, float g, float b, float alpha) const;
-    void drawWithOpenGL(const sp<const DisplayDevice>& hw,
+    void drawWithOpenGL(const RenderArea& renderArea,
             bool useIdentityTransform) const;
 
     // Temporary - Used only for LEGACY camera mode.
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
new file mode 100644
index 0000000..6225df1
--- /dev/null
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -0,0 +1,34 @@
+#include "RenderArea.h"
+
+namespace android {
+
+/*
+ * Checks that the requested width and height are valid and updates them to the render area
+ * dimensions if they are set to 0
+ */
+status_t RenderArea::updateDimensions() {
+    // get screen geometry
+
+    uint32_t width = getWidth();
+    uint32_t height = getHeight();
+
+    if (mRotationFlags & Transform::ROT_90) {
+        std::swap(width, height);
+    }
+
+    if ((mReqWidth > width) || (mReqHeight > height)) {
+        ALOGE("size mismatch (%d, %d) > (%d, %d)", mReqWidth, mReqHeight, width, height);
+        return BAD_VALUE;
+    }
+
+    if (mReqWidth == 0) {
+        mReqWidth = width;
+    }
+    if (mReqHeight == 0) {
+        mReqHeight = height;
+    }
+
+    return NO_ERROR;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
new file mode 100644
index 0000000..faf1ec6
--- /dev/null
+++ b/services/surfaceflinger/RenderArea.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "Transform.h"
+
+namespace android {
+
+class RenderArea {
+public:
+    RenderArea(uint32_t reqHeight, uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+          : mReqHeight(reqHeight), mReqWidth(reqWidth) {
+        mRotationFlags = Transform::fromRotation(rotation);
+    }
+
+    virtual ~RenderArea() = default;
+
+    virtual const Transform& getTransform() const = 0;
+    virtual Rect getBounds() const = 0;
+    virtual int getHeight() const = 0;
+    virtual int getWidth() const = 0;
+    virtual bool isSecure() const = 0;
+    virtual bool needsFiltering() const = 0;
+    virtual Rect getSourceCrop() const = 0;
+
+    int getReqHeight() const { return mReqHeight; };
+    int getReqWidth() const { return mReqWidth; };
+    Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
+#ifdef USE_HWC2
+    virtual bool getWideColorSupport() const = 0;
+    virtual android_color_mode_t getActiveColorMode() const = 0;
+#endif
+
+    status_t updateDimensions();
+
+private:
+    uint32_t mReqHeight;
+    uint32_t mReqWidth;
+    Transform::orientation_flags mRotationFlags;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 05c76fc..875bef1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2650,6 +2650,7 @@
 {
     ALOGV("doComposeSurfaces");
 
+    const DisplayRenderArea renderArea(displayDevice);
     const auto hwcId = displayDevice->getHwcDisplayId();
 
     mat4 oldColorMatrix;
@@ -2759,12 +2760,12 @@
                                 && hasClientComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
-                            layer->clearWithOpenGL(displayDevice);
+                            layer->clearWithOpenGL(renderArea);
                         }
                         break;
                     }
                     case HWC2::Composition::Client: {
-                        layer->draw(displayDevice, clip);
+                        layer->draw(renderArea, clip);
                         break;
                     }
                     default:
@@ -2781,7 +2782,7 @@
             const Region clip(dirty.intersect(
                     displayTransform.transform(layer->visibleRegion)));
             if (!clip.isEmpty()) {
-                layer->draw(displayDevice, clip);
+                layer->draw(renderArea, clip);
             }
         }
     }
@@ -3482,12 +3483,18 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args) {
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
+
+    if (asProto) {
+        // Return early as SurfaceFlinger does not support dumping sections in proto format
+        return OK;
+    }
+
     if ((uid != AID_SHELL) &&
             !PermissionCache::checkPermission(sDump, pid, uid)) {
         result.appendFormat("Permission Denial: "
@@ -4029,6 +4036,17 @@
             }
             break;
         }
+        case CAPTURE_LAYERS: {
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int uid = ipc->getCallingUid();
+            if ((uid != AID_GRAPHICS) &&
+                !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+                ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+                return PERMISSION_DENIED;
+            }
+            break;
+        }
     }
     return OK;
 }
@@ -4228,35 +4246,6 @@
     repaintEverythingLocked();
 }
 
-// Checks that the requested width and height are valid and updates them to the display dimensions
-// if they are set to 0
-static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
-                                       Transform::orientation_flags rotation,
-                                       uint32_t* requestedWidth, uint32_t* requestedHeight) {
-    // get screen geometry
-    uint32_t displayWidth = displayDevice->getWidth();
-    uint32_t displayHeight = displayDevice->getHeight();
-
-    if (rotation & Transform::ROT_90) {
-        std::swap(displayWidth, displayHeight);
-    }
-
-    if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) {
-        ALOGE("size mismatch (%d, %d) > (%d, %d)",
-                *requestedWidth, *requestedHeight, displayWidth, displayHeight);
-        return BAD_VALUE;
-    }
-
-    if (*requestedWidth == 0) {
-        *requestedWidth = displayWidth;
-    }
-    if (*requestedHeight == 0) {
-        *requestedHeight = displayHeight;
-    }
-
-    return NO_ERROR;
-}
-
 // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
 class WindowDisconnector {
 public:
@@ -4305,50 +4294,86 @@
 }
 
 status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+                                       const sp<IGraphicBufferProducer>& producer, Rect sourceCrop,
+                                       uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
+                                       int32_t maxLayerZ, bool useIdentityTransform,
+                                       ISurfaceComposer::Rotation rotation) {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(display == 0))
-        return BAD_VALUE;
+    if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
+
+    const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+    DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+
+    auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
+                                    device, minLayerZ, maxLayerZ, std::placeholders::_1);
+    return captureScreenCommon(renderArea, traverseLayers, producer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
+                                       const sp<IGraphicBufferProducer>& producer,
+                                       ISurfaceComposer::Rotation rotation) {
+    ATRACE_CALL();
+
+    class LayerRenderArea : public RenderArea {
+    public:
+        LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation)
+              : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w,
+                           rotation),
+                mLayer(layer) {}
+        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());
+        }
+        Rect getBounds() const override {
+            const Layer::State& layerState(mLayer->getDrawingState());
+            return Rect(layerState.active.w, layerState.active.h);
+        }
+        int getHeight() const override { return mLayer->getDrawingState().active.h; }
+        int getWidth() const override { return mLayer->getDrawingState().active.w; }
+        bool isSecure() const override { return false; }
+        bool needsFiltering() const override { return false; }
+
+        Rect getSourceCrop() const override { return getBounds(); }
+        bool getWideColorSupport() const override { return false; }
+        android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; }
+
+    private:
+        const sp<Layer>& mLayer;
+    };
+
+    auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
+    auto parent = layerHandle->owner.promote();
+
+    LayerRenderArea renderArea(parent, rotation);
+    auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
+        parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+            if (!layer->isVisible()) {
+                return;
+            }
+            visitor(layer);
+        });
+    };
+    return captureScreenCommon(renderArea, traverseLayers, producer, false);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+                                             TraverseLayersFunction traverseLayers,
+                                             const sp<IGraphicBufferProducer>& producer,
+                                             bool useIdentityTransform) {
+    ATRACE_CALL();
 
     if (CC_UNLIKELY(producer == 0))
         return BAD_VALUE;
 
+    renderArea.updateDimensions();
+
     // if we have secure windows on this display, never allow the screen capture
     // unless the producer interface is local (i.e.: we can take a screenshot for
     // ourselves).
     bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
 
-    // Convert to surfaceflinger's internal rotation type.
-    Transform::orientation_flags rotationFlags;
-    switch (rotation) {
-        case ISurfaceComposer::eRotateNone:
-            rotationFlags = Transform::ROT_0;
-            break;
-        case ISurfaceComposer::eRotate90:
-            rotationFlags = Transform::ROT_90;
-            break;
-        case ISurfaceComposer::eRotate180:
-            rotationFlags = Transform::ROT_180;
-            break;
-        case ISurfaceComposer::eRotate270:
-            rotationFlags = Transform::ROT_270;
-            break;
-        default:
-            rotationFlags = Transform::ROT_0;
-            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
-            break;
-    }
-
-    { // Autolock scope
-        Mutex::Autolock lock(mStateLock);
-        sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
-        updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight);
-    }
-
     // create a surface (because we're a producer, and we need to
     // dequeue/queue a buffer)
     sp<Surface> surface = new Surface(producer, false);
@@ -4369,9 +4394,9 @@
     WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
 
     ANativeWindowBuffer* buffer = nullptr;
-    result = getWindowBuffer(window, reqWidth, reqHeight,
-            hasWideColorDisplay && !mForceNativeColorMode,
-            getRenderEngine().usesWideColor(), &buffer);
+    result = getWindowBuffer(window, renderArea.getReqWidth(), renderArea.getReqHeight(),
+                             hasWideColorDisplay && !mForceNativeColorMode,
+                             getRenderEngine().usesWideColor(), &buffer);
     if (result != NO_ERROR) {
         return result;
     }
@@ -4399,10 +4424,8 @@
         int fd = -1;
         {
             Mutex::Autolock _l(mStateLock);
-            sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
-            result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight,
-                                             minLayerZ, maxLayerZ, useIdentityTransform,
-                                             rotationFlags, isLocalScreenshot, &fd);
+            result = captureScreenImplLocked(renderArea, traverseLayers, buffer,
+                                             useIdentityTransform, isLocalScreenshot, &fd);
         }
 
         {
@@ -4431,84 +4454,66 @@
         // queueBuffer takes ownership of syncFd
         result = window->queueBuffer(window, buffer, syncFd);
     }
-
     return result;
 }
 
-
-void SurfaceFlinger::renderScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
-{
+void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
+                                            TraverseLayersFunction traverseLayers, bool yswap,
+                                            bool useIdentityTransform) {
     ATRACE_CALL();
+
     RenderEngine& engine(getRenderEngine());
 
     // get screen geometry
-    const int32_t hw_w = hw->getWidth();
-    const int32_t hw_h = hw->getHeight();
-    const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
-                           static_cast<int32_t>(reqHeight) != hw_h;
+    const auto raWidth = renderArea.getWidth();
+    const auto raHeight = renderArea.getHeight();
+
+    const auto reqWidth = renderArea.getReqWidth();
+    const auto reqHeight = renderArea.getReqHeight();
+    Rect sourceCrop = renderArea.getSourceCrop();
+
+    const bool filtering = static_cast<int32_t>(reqWidth) != raWidth ||
+            static_cast<int32_t>(reqHeight) != raHeight;
 
     // if a default or invalid sourceCrop is passed in, set reasonable values
-    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
-            !sourceCrop.isValid()) {
+    if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || !sourceCrop.isValid()) {
         sourceCrop.setLeftTop(Point(0, 0));
-        sourceCrop.setRightBottom(Point(hw_w, hw_h));
+        sourceCrop.setRightBottom(Point(raWidth, raHeight));
     }
 
     // ensure that sourceCrop is inside screen
     if (sourceCrop.left < 0) {
         ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
     }
-    if (sourceCrop.right > hw_w) {
-        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
+    if (sourceCrop.right > raWidth) {
+        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
     }
     if (sourceCrop.top < 0) {
         ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
     }
-    if (sourceCrop.bottom > hw_h) {
-        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
+    if (sourceCrop.bottom > raHeight) {
+        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
-#ifdef USE_HWC2
-     engine.setWideColor(hw->getWideColorSupport() && !mForceNativeColorMode);
-     engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : hw->getActiveColorMode());
-#endif
+    engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode);
+    engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : renderArea.getActiveColorMode());
 
     // make sure to clear all GL error flags
     engine.checkErrors();
 
     // set-up our viewport
-    engine.setViewportAndProjection(
-        reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
+    engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, raHeight, yswap,
+                                    renderArea.getRotationFlags());
     engine.disableTexturing();
 
     // redraw the screen entirely...
     engine.clearWithColor(0, 0, 0, 1);
 
-    // We loop through the first level of layers without traversing,
-    // as we need to interpret min/max layer Z in the top level Z space.
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
-            continue;
-        }
-        const Layer::State& state(layer->getDrawingState());
-        if (state.z < minLayerZ || state.z > maxLayerZ) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (!layer->isVisible()) {
-                return;
-            }
-            if (filtering) layer->setFiltering(true);
-            layer->draw(hw, useIdentityTransform);
-            if (filtering) layer->setFiltering(false);
-        });
-    }
-
-    hw->setViewportAndProjection();
+    traverseLayers([&](Layer* layer) {
+        if (filtering) layer->setFiltering(true);
+        layer->draw(renderArea, useIdentityTransform);
+        if (filtering) layer->setFiltering(false);
+    });
 }
 
 // A simple RAII class that holds an EGLImage and destroys it either:
@@ -4531,27 +4536,18 @@
     EGLImageKHR mImage;
 };
 
-status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw,
-                                                 ANativeWindowBuffer* buffer, Rect sourceCrop,
-                                                 uint32_t reqWidth, uint32_t reqHeight,
-                                                 int32_t minLayerZ, int32_t maxLayerZ,
-                                                 bool useIdentityTransform,
-                                                 Transform::orientation_flags rotation,
-                                                 bool isLocalScreenshot, int* outSyncFd) {
+status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
+                                                 TraverseLayersFunction traverseLayers,
+                                                 ANativeWindowBuffer* buffer,
+                                                 bool useIdentityTransform, bool isLocalScreenshot,
+                                                 int* outSyncFd) {
     ATRACE_CALL();
 
     bool secureLayerIsVisible = false;
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        const Layer::State& state(layer->getDrawingState());
-        if (!layer->belongsToDisplay(hw->getLayerStack(), false) ||
-                (state.z < minLayerZ || state.z > maxLayerZ)) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
-            secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
-                    layer->isSecure());
-        });
-    }
+
+    traverseLayers([&](Layer* layer) {
+        secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure());
+    });
 
     if (!isLocalScreenshot && secureLayerIsVisible) {
         ALOGW("FB is protected: PERMISSION_DENIED");
@@ -4582,9 +4578,7 @@
     // via an FBO, which means we didn't have to create
     // an EGLSurface and therefore we're not
     // dependent on the context's EGLConfig.
-    renderScreenImplLocked(
-        hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
-        useIdentityTransform, rotation);
+    renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
 
     // Attempt to create a sync khr object that can produce a sync point. If that
     // isn't available, create a non-dupable sync object in the fallback path and
@@ -4625,46 +4619,40 @@
     *outSyncFd = syncFd;
 
     if (DEBUG_SCREENSHOTS) {
+        const auto reqWidth = renderArea.getReqWidth();
+        const auto reqHeight = renderArea.getReqHeight();
+
         uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
         getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
-        checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
-                hw, minLayerZ, maxLayerZ);
+        checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
         delete [] pixels;
     }
 
     // destroy our image
     imageHolder.destroy();
-
     return NO_ERROR;
 }
 
 void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
-        const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
+                                     TraverseLayersFunction traverseLayers) {
     if (DEBUG_SCREENSHOTS) {
-        for (size_t y=0 ; y<h ; y++) {
-            uint32_t const * p = (uint32_t const *)vaddr + y*s;
-            for (size_t x=0 ; x<w ; x++) {
+        for (size_t y = 0; y < h; y++) {
+            uint32_t const* p = (uint32_t const*)vaddr + y * s;
+            for (size_t x = 0; x < w; x++) {
                 if (p[x] != 0xFF000000) return;
             }
         }
-        ALOGE("*** we just took a black screenshot ***\n"
-                "requested minz=%d, maxz=%d, layerStack=%d",
-                minLayerZ, maxLayerZ, hw->getLayerStack());
+        ALOGE("*** we just took a black screenshot ***");
 
         size_t i = 0;
-        for (const auto& layer : mDrawingState.layersSortedByZ) {
+        traverseLayers([&](Layer* layer) {
             const Layer::State& state(layer->getDrawingState());
-            if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ &&
-                    state.z <= maxLayerZ) {
-                layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-                    ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
-                            layer->isVisible() ? '+' : '-',
-                            i, layer->getName().string(), layer->getLayerStack(), state.z,
-                            layer->isVisible(), state.flags, static_cast<float>(state.color.a));
-                    i++;
-                });
-            }
-        }
+            ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
+                  layer->isVisible() ? '+' : '-', i, layer->getName().string(),
+                  layer->getLayerStack(), state.z, layer->isVisible(), state.flags,
+                  static_cast<float>(state.color.a));
+            i++;
+        });
     }
 }
 
@@ -4678,6 +4666,28 @@
     layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
 }
 
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ,
+                                             int32_t maxLayerZ,
+                                             const LayerVector::Visitor& visitor) {
+    // We loop through the first level of layers without traversing,
+    // as we need to interpret min/max layer Z in the top level Z space.
+    for (const auto& layer : mDrawingState.layersSortedByZ) {
+        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+            continue;
+        }
+        const Layer::State& state(layer->getDrawingState());
+        if (state.z < minLayerZ || state.z > maxLayerZ) {
+            continue;
+        }
+        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+            if (!layer->isVisible()) {
+                return;
+            }
+            visitor(layer);
+        });
+    }
+}
+
 }; // namespace android
 
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bd98c8f..25ccb89 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -77,6 +77,7 @@
 #include <string>
 #include <thread>
 #include <utility>
+#include "RenderArea.h"
 
 #include <layerproto/LayerProtoHeader.h>
 
@@ -97,6 +98,8 @@
 class VSyncSource;
 class InjectVSyncSource;
 
+typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction;
+
 namespace dvr {
 class VrFlinger;
 } // namespace dvr
@@ -303,6 +306,9 @@
             Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
             int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
+    virtual status_t captureLayers(const sp<IBinder>& parentHandle,
+                                   const sp<IGraphicBufferProducer>& producer,
+                                   ISurfaceComposer::Rotation rotation);
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats);
     virtual status_t getDisplayConfigs(const sp<IBinder>& display,
@@ -448,28 +454,26 @@
 
     void startBootAnim();
 
-    void renderScreenImplLocked(
-            const sp<const DisplayDevice>& hw,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation);
+    void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+                                bool yswap, bool useIdentityTransform);
+
+    status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+                                 const sp<IGraphicBufferProducer>& producer,
+                                 bool useIdentityTransform);
 
 #ifdef USE_HWC2
-    status_t captureScreenImplLocked(const sp<const DisplayDevice>& device,
-                                     ANativeWindowBuffer* buffer, Rect sourceCrop,
-                                     uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
-                                     int32_t maxLayerZ, bool useIdentityTransform,
-                                     Transform::orientation_flags rotation, bool isLocalScreenshot,
-                                     int* outSyncFd);
+    status_t captureScreenImplLocked(const RenderArea& renderArea,
+                                     TraverseLayersFunction traverseLayers,
+                                     ANativeWindowBuffer* buffer, bool useIdentityTransform,
+                                     bool isLocalScreenshot, int* outSyncFd);
 #else
-    status_t captureScreenImplLocked(
-            const sp<const DisplayDevice>& hw,
-            const sp<IGraphicBufferProducer>& producer,
-            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-            int32_t minLayerZ, int32_t maxLayerZ,
-            bool useIdentityTransform, Transform::orientation_flags rotation,
-            bool isLocalScreenshot);
+    status_t captureScreenImplLocked(const RenderArea& renderArea,
+                                     TraverseLayersFunction traverseLayers,
+                                     const sp<IGraphicBufferProducer>& producer,
+                                     bool useIdentityTransform, bool isLocalScreenshot);
 #endif
+    void traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
+                                 int32_t maxLayerZ, const LayerVector::Visitor& visitor);
 
     sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
 
@@ -600,11 +604,14 @@
      * Debugging & dumpsys
      */
 public:
-    status_t dumpCritical(int fd, const Vector<String16>& /*args*/) {
-        return doDump(fd, Vector<String16>());
+    status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) {
+        return doDump(fd, Vector<String16>(), asProto);
     }
 
-    status_t dumpAll(int fd, const Vector<String16>& args) { return doDump(fd, args); }
+    status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) {
+        return doDump(fd, args, asProto);
+    }
+
 private:
     void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
@@ -613,8 +620,7 @@
     bool startDdmConnection();
     void appendSfConfigString(String8& result) const;
     void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
-            const sp<const DisplayDevice>& hw,
-            int32_t minLayerZ, int32_t maxLayerZ);
+                         TraverseLayersFunction traverseLayers);
 
     void logFrameStats();
 
@@ -631,7 +637,7 @@
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
     }
-    status_t doDump(int fd, const Vector<String16>& args);
+    status_t doDump(int fd, const Vector<String16>& args, bool asProto);
 
 #ifdef USE_HWC2
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index ed7641f..952023e 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2212,6 +2212,8 @@
 
 bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
 {
+    DisplayRenderArea renderArea(hw);
+
     RenderEngine& engine(getRenderEngine());
     const int32_t id = hw->getHwcDisplayId();
     HWComposer& hwc(getHwComposer());
@@ -2303,12 +2305,12 @@
                                 && hasGlesComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
-                            layer->clearWithOpenGL(hw);
+                            layer->clearWithOpenGL(renderArea);
                         }
                         break;
                     }
                     case HWC_FRAMEBUFFER: {
-                        layer->draw(hw, clip);
+                        layer->draw(renderArea, clip);
                         break;
                     }
                     case HWC_FRAMEBUFFER_TARGET: {
@@ -2328,7 +2330,7 @@
             const Region clip(dirty.intersect(
                     tr.transform(layer->visibleRegion)));
             if (!clip.isEmpty()) {
-                layer->draw(hw, clip);
+                layer->draw(renderArea, clip);
             }
         }
     }
@@ -3007,13 +3009,18 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
+
+    if (asProto) {
+        // Return early as SurfaceFlinger does not support dumping sections in proto format
+        return OK;
+    }
+
     if ((uid != AID_SHELL) &&
             !PermissionCache::checkPermission(sDump, pid, uid)) {
         result.appendFormat("Permission Denial: "
@@ -3493,6 +3500,18 @@
             }
             break;
         }
+        case CAPTURE_LAYERS:
+        {
+            IPCThreadState* ipc = IPCThreadState::self();
+            const int pid = ipc->getCallingPid();
+            const int uid = ipc->getCallingUid();
+            if ((uid != AID_GRAPHICS) &&
+                !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+                ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid);
+                return PERMISSION_DENIED;
+            }
+            break;
+        }
     }
 
     status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
@@ -3766,16 +3785,72 @@
     }
 };
 
-
 status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
-
+    const sp<IGraphicBufferProducer>& producer,
+    Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+    int32_t minLayerZ, int32_t maxLayerZ,
+    bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+    ATRACE_CALL();
     if (CC_UNLIKELY(display == 0))
         return BAD_VALUE;
 
+    const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+    DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+
+    auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
+                                    device, minLayerZ, maxLayerZ, std::placeholders::_1);
+    return captureScreenCommon(renderArea, traverseLayers, producer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
+                                       const sp<IGraphicBufferProducer>& producer,
+                                       ISurfaceComposer::Rotation rotation) {
+    ATRACE_CALL();
+    class LayerRenderArea : public RenderArea {
+    public:
+        LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation)
+              : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w,
+                           rotation),
+                mLayer(layer) {}
+        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());
+        }
+        Rect getBounds() const override {
+            const Layer::State& layerState(mLayer->getDrawingState());
+            return Rect(layerState.active.w, layerState.active.h);
+        }
+        int getHeight() const override { return mLayer->getDrawingState().active.h; }
+        int getWidth() const override { return mLayer->getDrawingState().active.w; }
+        bool isSecure() const override { return false; }
+        bool needsFiltering() const override { return false; }
+
+        Rect getSourceCrop() const override { return getBounds(); }
+
+    private:
+        const sp<Layer>& mLayer;
+    };
+
+    auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
+    auto parent = layerHandle->owner.promote();
+
+    LayerRenderArea renderArea(parent, rotation);
+    auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
+        parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+            if (!layer->isVisible()) {
+                return;
+            }
+            visitor(layer);
+        });
+    };
+    return captureScreenCommon(renderArea, traverseLayers, producer, false);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+                                             TraverseLayersFunction traverseLayers,
+                                             const sp<IGraphicBufferProducer>& producer,
+                                             bool useIdentityTransform) {
     if (CC_UNLIKELY(producer == 0))
         return BAD_VALUE;
 
@@ -3784,64 +3859,33 @@
     // ourselves).
     bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
 
-    // Convert to surfaceflinger's internal rotation type.
-    Transform::orientation_flags rotationFlags;
-    switch (rotation) {
-        case ISurfaceComposer::eRotateNone:
-            rotationFlags = Transform::ROT_0;
-            break;
-        case ISurfaceComposer::eRotate90:
-            rotationFlags = Transform::ROT_90;
-            break;
-        case ISurfaceComposer::eRotate180:
-            rotationFlags = Transform::ROT_180;
-            break;
-        case ISurfaceComposer::eRotate270:
-            rotationFlags = Transform::ROT_270;
-            break;
-        default:
-            rotationFlags = Transform::ROT_0;
-            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
-            break;
-    }
-
     class MessageCaptureScreen : public MessageBase {
         SurfaceFlinger* flinger;
-        sp<IBinder> display;
+        const RenderArea* renderArea;
+        TraverseLayersFunction traverseLayers;
         sp<IGraphicBufferProducer> producer;
-        Rect sourceCrop;
-        uint32_t reqWidth, reqHeight;
-        int32_t minLayerZ,maxLayerZ;
         bool useIdentityTransform;
-        Transform::orientation_flags rotation;
         status_t result;
         bool isLocalScreenshot;
     public:
-        MessageCaptureScreen(SurfaceFlinger* flinger,
-                const sp<IBinder>& display,
-                const sp<IGraphicBufferProducer>& producer,
-                Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                int32_t minLayerZ, int32_t maxLayerZ,
-                bool useIdentityTransform,
-                Transform::orientation_flags rotation,
-                bool isLocalScreenshot)
-            : flinger(flinger), display(display), producer(producer),
-              sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
-              minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
-              useIdentityTransform(useIdentityTransform),
-              rotation(rotation), result(PERMISSION_DENIED),
-              isLocalScreenshot(isLocalScreenshot)
-        {
-        }
+        MessageCaptureScreen(SurfaceFlinger* flinger, const RenderArea* renderArea,
+                             TraverseLayersFunction traverseLayers,
+                             const sp<IGraphicBufferProducer>& producer, bool useIdentityTransform,
+                             bool isLocalScreenshot)
+              : flinger(flinger),
+                renderArea(renderArea),
+                traverseLayers(traverseLayers),
+                producer(producer),
+                useIdentityTransform(useIdentityTransform),
+                result(PERMISSION_DENIED),
+                isLocalScreenshot(isLocalScreenshot) {}
         status_t getResult() const {
             return result;
         }
         virtual bool handler() {
             Mutex::Autolock _l(flinger->mStateLock);
-            sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
-            result = flinger->captureScreenImplLocked(hw, producer,
-                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-                    useIdentityTransform, rotation, isLocalScreenshot);
+            result = flinger->captureScreenImplLocked(*renderArea, traverseLayers, producer,
+                                                      useIdentityTransform, isLocalScreenshot);
             static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
             return true;
         }
@@ -3855,9 +3899,8 @@
     // the asInterface() call below creates our "fake" BpGraphicBufferProducer
     // which does the marshaling work forwards to our "fake remote" above.
     sp<MessageBase> msg = new MessageCaptureScreen(this,
-            display, IGraphicBufferProducer::asInterface( wrapper ),
-            sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-            useIdentityTransform, rotationFlags, isLocalScreenshot);
+            &renderArea, traverseLayers, IGraphicBufferProducer::asInterface( wrapper ),
+            useIdentityTransform, isLocalScreenshot);
 
     status_t res = postMessageAsync(msg);
     if (res == NO_ERROR) {
@@ -3866,41 +3909,42 @@
     return res;
 }
 
-
-void SurfaceFlinger::renderScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
+void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+        bool yswap, bool useIdentityTransform)
 {
     ATRACE_CALL();
     RenderEngine& engine(getRenderEngine());
 
     // get screen geometry
-    const int32_t hw_w = hw->getWidth();
-    const int32_t hw_h = hw->getHeight();
-    const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
-                           static_cast<int32_t>(reqHeight) != hw_h;
+    const auto raWidth = renderArea.getWidth();
+    const auto raHeight = renderArea.getHeight();
+
+    const auto reqWidth = renderArea.getReqWidth();
+    const auto reqHeight = renderArea.getReqHeight();
+    Rect sourceCrop = renderArea.getSourceCrop();
+
+    const bool filtering = static_cast<int32_t>(reqWidth) != raWidth ||
+        static_cast<int32_t>(reqHeight) != raHeight;
 
     // if a default or invalid sourceCrop is passed in, set reasonable values
     if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
             !sourceCrop.isValid()) {
         sourceCrop.setLeftTop(Point(0, 0));
-        sourceCrop.setRightBottom(Point(hw_w, hw_h));
+        sourceCrop.setRightBottom(Point(raWidth, raHeight));
     }
 
     // ensure that sourceCrop is inside screen
     if (sourceCrop.left < 0) {
         ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
     }
-    if (sourceCrop.right > hw_w) {
-        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
+    if (sourceCrop.right > raWidth) {
+        ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, raWidth);
     }
     if (sourceCrop.top < 0) {
         ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
     }
-    if (sourceCrop.bottom > hw_h) {
-        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
+    if (sourceCrop.bottom > raHeight) {
+        ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
     // make sure to clear all GL error flags
@@ -3908,77 +3952,35 @@
 
     // set-up our viewport
     engine.setViewportAndProjection(
-        reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
+        reqWidth, reqHeight, sourceCrop, raHeight, yswap, renderArea.getRotationFlags());
     engine.disableTexturing();
 
     // redraw the screen entirely...
     engine.clearWithColor(0, 0, 0, 1);
 
-    // We loop through the first level of layers without traversing,
-    // as we need to interpret min/max layer Z in the top level Z space.
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (layer->getLayerStack() != hw->getLayerStack()) {
-            continue;
-        }
-        const Layer::State& state(layer->getDrawingState());
-        if (state.z < minLayerZ || state.z > maxLayerZ) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (!layer->isVisible()) {
-                return;
-            }
-            if (filtering) layer->setFiltering(true);
-            layer->draw(hw, useIdentityTransform);
-            if (filtering) layer->setFiltering(false);
-        });
-    }
+    traverseLayers([&](Layer* layer) {
+        if (filtering) layer->setFiltering(true);
+        layer->draw(renderArea, useIdentityTransform);
+        if (filtering) layer->setFiltering(false);
+    });
 
     // compositionComplete is needed for older driver
-    hw->compositionComplete();
-    hw->setViewportAndProjection();
+//    hw->compositionComplete();
+//    hw->setViewportAndProjection();
 }
 
-
-status_t SurfaceFlinger::captureScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, Transform::orientation_flags rotation,
-        bool isLocalScreenshot)
-{
+status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
+                                                 TraverseLayersFunction traverseLayers,
+                                                 const sp<IGraphicBufferProducer>& producer,
+                                                 bool useIdentityTransform,
+                                                 bool isLocalScreenshot) {
     ATRACE_CALL();
 
-    // get screen geometry
-    uint32_t hw_w = hw->getWidth();
-    uint32_t hw_h = hw->getHeight();
-
-    if (rotation & Transform::ROT_90) {
-        std::swap(hw_w, hw_h);
-    }
-
-    if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
-        ALOGE("size mismatch (%d, %d) > (%d, %d)",
-                reqWidth, reqHeight, hw_w, hw_h);
-        return BAD_VALUE;
-    }
-
-    reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
-    reqHeight = (!reqHeight) ? hw_h : reqHeight;
-
     bool secureLayerIsVisible = false;
-    for (const auto& layer : mDrawingState.layersSortedByZ) {
-        const Layer::State& state(layer->getDrawingState());
-        if ((layer->getLayerStack() != hw->getLayerStack()) ||
-                (state.z < minLayerZ || state.z > maxLayerZ)) {
-            continue;
-        }
-        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer *layer) {
-            secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
-                    layer->isSecure());
-        });
-    }
+    traverseLayers([&](Layer *layer) {
+        secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() &&
+            layer->isSecure());
+    });
 
     if (!isLocalScreenshot && secureLayerIsVisible) {
         ALOGW("FB is protected: PERMISSION_DENIED");
@@ -3996,7 +3998,8 @@
                         GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
 
         int err = 0;
-        err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
+        err = native_window_set_buffers_dimensions(window, renderArea.getReqWidth(),
+                                                   renderArea.getReqHeight());
         err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
         err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
         err |= native_window_set_usage(window, usage);
@@ -4022,9 +4025,7 @@
                         // via an FBO, which means we didn't have to create
                         // an EGLSurface and therefore we're not
                         // dependent on the context's EGLConfig.
-                        renderScreenImplLocked(
-                            hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
-                            useIdentityTransform, rotation);
+                        renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
 
                         // Attempt to create a sync khr object that can produce a sync point. If that
                         // isn't available, create a non-dupable sync object in the fallback path and
@@ -4064,10 +4065,12 @@
                             }
                         }
                         if (DEBUG_SCREENSHOTS) {
-                            uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
-                            getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
-                            checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
-                                    hw, minLayerZ, maxLayerZ);
+                            uint32_t* pixels = new uint32_t[renderArea.getReqWidth() *
+                                                            renderArea.getReqHeight()];
+                            getRenderEngine().readPixels(0, 0, renderArea.getReqWidth(),
+                                                         renderArea.getReqHeight(), pixels);
+                            checkScreenshot(renderArea.getReqWidth(), renderArea.getReqHeight(),
+                                            renderArea.getReqWidth(), pixels, traverseLayers);
                             delete [] pixels;
                         }
 
@@ -4097,7 +4100,7 @@
 }
 
 void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
-        const sp<const DisplayDevice>& hw, int32_t minLayerZ, int32_t maxLayerZ) {
+    TraverseLayersFunction traverseLayers) {
     if (DEBUG_SCREENSHOTS) {
         for (size_t y=0 ; y<h ; y++) {
             uint32_t const * p = (uint32_t const *)vaddr + y*s;
@@ -4105,23 +4108,17 @@
                 if (p[x] != 0xFF000000) return;
             }
         }
-        ALOGE("*** we just took a black screenshot ***\n"
-                "requested minz=%d, maxz=%d, layerStack=%d",
-                minLayerZ, maxLayerZ, hw->getLayerStack());
+        ALOGE("*** we just took a black screenshot ***");
+
         size_t i = 0;
-        for (const auto& layer : mDrawingState.layersSortedByZ) {
+        traverseLayers([&](Layer* layer) {
             const Layer::State& state(layer->getDrawingState());
-            if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
-                    state.z <= maxLayerZ) {
-                layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-                    ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
-                            layer->isVisible() ? '+' : '-',
-                            i, layer->getName().string(), layer->getLayerStack(), state.z,
-                            layer->isVisible(), state.flags, static_cast<float>(state.color.a));
-                    i++;
-                });
-            }
-        }
+            ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
+                layer->isVisible() ? '+' : '-',
+                i, layer->getName().string(), layer->getLayerStack(), state.z,
+                layer->isVisible(), state.flags, static_cast<float>(state.color.a));
+            i++;
+        });
     }
 }
 
@@ -4135,6 +4132,28 @@
     layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
 }
 
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw,
+    int32_t minLayerZ, int32_t maxLayerZ, const LayerVector::Visitor& visitor) {
+
+    // We loop through the first level of layers without traversing,
+    // as we need to interpret min/max layer Z in the top level Z space.
+    for (const auto& layer : mDrawingState.layersSortedByZ) {
+        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+            continue;
+        }
+        const Layer::State& state(layer->getDrawingState());
+        if (state.z < minLayerZ || state.z > maxLayerZ) {
+            continue;
+        }
+        layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+            if (!layer->isVisible()) {
+                return;
+            }
+            visitor(layer);
+        });
+    }
+}
+
 }; // namespace android
 
 
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 6be9ae2..37925a1 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -20,8 +20,8 @@
 #include <utils/String8.h>
 #include <ui/Region.h>
 
-#include "clz.h"
 #include "Transform.h"
+#include "clz.h"
 
 // ---------------------------------------------------------------------------
 
@@ -388,6 +388,23 @@
     ALOGD("%.4f  %.4f  %.4f", m[0][2], m[1][2], m[2][2]);
 }
 
+Transform::orientation_flags Transform::fromRotation(ISurfaceComposer::Rotation rotation) {
+    // Convert to surfaceflinger's internal rotation type.
+    switch (rotation) {
+        case ISurfaceComposer::eRotateNone:
+            return Transform::ROT_0;
+        case ISurfaceComposer::eRotate90:
+            return Transform::ROT_90;
+        case ISurfaceComposer::eRotate180:
+            return Transform::ROT_180;
+        case ISurfaceComposer::eRotate270:
+            return Transform::ROT_270;
+        default:
+            ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
+            return Transform::ROT_0;
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 6640a13..bfc66ec 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -25,6 +25,8 @@
 #include <math/vec2.h>
 #include <math/vec3.h>
 
+#include <gui/ISurfaceComposer.h>
+
 #include <hardware/hardware.h>
 
 namespace android {
@@ -51,6 +53,8 @@
                 ROT_INVALID = 0x80
             };
 
+            static orientation_flags fromRotation(ISurfaceComposer::Rotation rotation);
+
             enum type_mask {
                 IDENTITY            = 0,
                 TRANSLATE           = 0x1,
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 6554167..e6f2ce7 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -14,10 +14,16 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
 #include <layerproto/LayerProtoParser.h>
+#include <ui/DebugUtils.h>
+
+using android::base::StringAppendF;
+using android::base::StringPrintf;
 
 namespace android {
 namespace surfaceflinger {
+
 bool sortLayers(const LayerProtoParser::Layer* lhs, const LayerProtoParser::Layer* rhs) {
     uint32_t ls = lhs->layerStack;
     uint32_t rs = rhs->layerStack;
@@ -219,5 +225,62 @@
     return result;
 }
 
+std::string LayerProtoParser::ActiveBuffer::to_string() const {
+    return StringPrintf("[%4ux%4u:%4u,%s]", width, height, stride,
+                        decodePixelFormat(format).c_str());
+}
+
+std::string LayerProtoParser::Transform::to_string() const {
+    return StringPrintf("[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(dsdx),
+                        static_cast<double>(dtdx), static_cast<double>(dsdy),
+                        static_cast<double>(dtdy));
+}
+
+std::string LayerProtoParser::Rect::to_string() const {
+    return StringPrintf("[%3d, %3d, %3d, %3d]", 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),
+                         static_cast<int>(rects.size()));
+
+    for (auto& rect : rects) {
+        StringAppendF(&result, "    %s\n", rect.to_string().c_str());
+    }
+
+    return result;
+}
+
+std::string LayerProtoParser::Layer::to_string() const {
+    std::string result;
+    StringAppendF(&result, "+ %s (%s)\n", type.c_str(), name.c_str());
+    result.append(transparentRegion.to_string("TransparentRegion").c_str());
+    result.append(visibleRegion.to_string("VisibleRegion").c_str());
+    result.append(damageRegion.to_string("SurfaceDamageRegion").c_str());
+
+    StringAppendF(&result, "      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ", layerStack,
+                  z, static_cast<double>(position.x), static_cast<double>(position.y), size.x,
+                  size.y);
+
+    StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(),
+                  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, "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);
+    StringAppendF(&result, "tr=%s", transform.to_string().c_str());
+    result.append("\n");
+    StringAppendF(&result, "      parent=%s\n", parent == nullptr ? "none" : parent->name.c_str());
+    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);
+
+    return result;
+}
+
 } // namespace surfaceflinger
 } // namespace android
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 7b94cef..78c6cd1 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -18,14 +18,9 @@
 
 #include <math/vec4.h>
 
-#include <android-base/stringprintf.h>
-#include <ui/DebugUtils.h>
 #include <unordered_map>
 #include <vector>
 
-using android::base::StringAppendF;
-using android::base::StringPrintf;
-
 namespace android {
 namespace surfaceflinger {
 
@@ -38,10 +33,7 @@
         uint32_t stride;
         int32_t format;
 
-        std::string to_string() const {
-            return StringPrintf("[%4ux%4u:%4u,%s]", width, height, stride,
-                                decodePixelFormat(format).c_str());
-        }
+        std::string to_string() const;
     };
 
     class Transform {
@@ -51,11 +43,7 @@
         float dsdy;
         float dtdy;
 
-        std::string to_string() const {
-            return StringPrintf("[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(dsdx),
-                                static_cast<double>(dtdx), static_cast<double>(dsdy),
-                                static_cast<double>(dtdy));
-        }
+        std::string to_string() const;
     };
 
     class Rect {
@@ -65,9 +53,7 @@
         int32_t right;
         int32_t bottom;
 
-        std::string to_string() const {
-            return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
-        }
+        std::string to_string() const;
     };
 
     class Region {
@@ -75,17 +61,7 @@
         uint64_t id;
         std::vector<Rect> rects;
 
-        std::string to_string(const char* what) const {
-            std::string result =
-                    StringPrintf("  Region %s (this=%lx count=%d)\n", what,
-                                 static_cast<unsigned long>(id), static_cast<int>(rects.size()));
-
-            for (auto& rect : rects) {
-                StringAppendF(&result, "    %s\n", rect.to_string().c_str());
-            }
-
-            return result;
-        }
+        std::string to_string(const char* what) const;
     };
 
     class Layer {
@@ -120,37 +96,7 @@
         int32_t queuedFrames;
         bool refreshPending;
 
-        std::string to_string() const {
-            std::string result;
-            StringAppendF(&result, "+ %s (%s)\n", type.c_str(), name.c_str());
-            result.append(transparentRegion.to_string("TransparentRegion").c_str());
-            result.append(visibleRegion.to_string("VisibleRegion").c_str());
-            result.append(damageRegion.to_string("SurfaceDamageRegion").c_str());
-
-            StringAppendF(&result, "      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
-                          layerStack, z, static_cast<double>(position.x),
-                          static_cast<double>(position.y), size.x, size.y);
-
-            StringAppendF(&result, "crop=%s, finalCrop=%s, ", crop.to_string().c_str(),
-                          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, "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);
-            StringAppendF(&result, "tr=%s", transform.to_string().c_str());
-            result.append("\n");
-            StringAppendF(&result, "      parent=%s\n",
-                          parent == nullptr ? "none" : parent->name.c_str());
-            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);
-
-            return result;
-        }
+        std::string to_string() const;
     };
 
     static std::vector<const Layer*> generateLayerTree(const LayersProto& layersProto);
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 6a24891..2a924ae 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -106,7 +106,7 @@
     // publish surface flinger
     sp<IServiceManager> sm(defaultServiceManager());
     sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
-                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
 
     // publish GpuService
     sp<GpuService> gpuservice = new GpuService();
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index f61a978..16a16a5 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -116,6 +116,60 @@
     CpuConsumer::LockedBuffer mBuf;
 };
 
+class CaptureLayer {
+public:
+    static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle) {
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        sp<IBinder> display(sf->getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain));
+        SurfaceComposerClient::Transaction().apply(true);
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer));
+        *sc = std::make_unique<CaptureLayer>(cpuConsumer);
+    }
+
+    void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuffer.format);
+        const uint8_t* img = static_cast<const uint8_t*>(mBuffer.data);
+        const uint8_t* pixel = img + (4 * (y * mBuffer.stride + x));
+        if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+            String8 err(String8::format("pixel @ (%3d, %3d): "
+                                            "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+                                        x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+            EXPECT_EQ(String8(), err) << err.string();
+        }
+    }
+
+    void expectFGColor(uint32_t x, uint32_t y) {
+        checkPixel(x, y, 195, 63, 63);
+    }
+
+    void expectBGColor(uint32_t x, uint32_t y) {
+        checkPixel(x, y, 63, 63, 195);
+    }
+
+    void expectChildColor(uint32_t x, uint32_t y) {
+        checkPixel(x, y, 200, 200, 200);
+    }
+
+    CaptureLayer(const sp<CpuConsumer>& cc) :
+        mCC(cc) {
+        EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuffer));
+    }
+
+    ~CaptureLayer() {
+        mCC->unlockBuffer(mBuffer);
+    }
+
+private:
+    sp<CpuConsumer> mCC;
+    CpuConsumer::LockedBuffer mBuffer;
+};
+
+
 class LayerUpdateTest : public ::testing::Test {
 protected:
     virtual void SetUp() {
@@ -837,6 +891,30 @@
     }
 }
 
+TEST_F(LayerUpdateTest, MergingTransactions) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before move");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(0, 12);
+        sc->expectFGColor(75, 75);
+        sc->expectBGColor(145, 145);
+    }
+
+    Transaction t1, t2;
+    t1.setPosition(mFGSurfaceControl, 128, 128);
+    t2.setPosition(mFGSurfaceControl, 0, 0);
+    // We expect that the position update from t2 now
+    // overwrites the position update from t1.
+    t1.merge(std::move(t2));
+    t1.apply();
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectFGColor(1, 1);
+    }
+}
+
 class ChildLayerTest : public LayerUpdateTest {
 protected:
     void SetUp() override {
@@ -1431,4 +1509,109 @@
     }
 }
 
+class ScreenCaptureTest : public LayerUpdateTest {
+protected:
+    std::unique_ptr<CaptureLayer> mCapture;
+};
+
+TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
+    auto bgHandle = mBGSurfaceControl->getHandle();
+    CaptureLayer::captureScreen(&mCapture, bgHandle);
+    mCapture->expectBGColor(0, 0);
+    // Doesn't capture FG layer which is at 64, 64
+    mCapture->expectBGColor(64, 64);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
+    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 layer and its child.
+    CaptureLayer::captureScreen(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
+    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);
+
+    sp<SurfaceControl> grandchild = mComposerClient->createSurface(
+        String8("Grandchild surface"), 5, 5,
+        PIXEL_FORMAT_RGBA_8888, 0, child.get());
+
+    fillSurfaceRGBA8(grandchild, 50, 50, 50);
+    SurfaceComposerClient::Transaction()
+        .show(child)
+        .setPosition(grandchild, 5, 5)
+        .show(grandchild)
+        .apply(true);
+
+    // Captures mFGSurfaceControl, its child, and the grandchild.
+    CaptureLayer::captureScreen(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+    mCapture->checkPixel(5, 5, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureChildOnly) {
+    sp<SurfaceControl> child = mComposerClient->createSurface(
+        String8("Child surface"),
+        10, 10, PIXEL_FORMAT_RGBA_8888,
+        0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    auto childHandle = child->getHandle();
+
+    SurfaceComposerClient::Transaction()
+        .setPosition(child, 5, 5)
+        .show(child)
+        .apply(true);
+
+    // Captures only the child layer, and not the parent.
+    CaptureLayer::captureScreen(&mCapture, childHandle);
+    mCapture->expectChildColor(0, 0);
+    mCapture->expectChildColor(9, 9);
+}
+
+TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
+    sp<SurfaceControl> child = mComposerClient->createSurface(
+        String8("Child surface"),
+        10, 10, PIXEL_FORMAT_RGBA_8888,
+        0, mFGSurfaceControl.get());
+    fillSurfaceRGBA8(child, 200, 200, 200);
+    auto childHandle = child->getHandle();
+
+    sp<SurfaceControl> grandchild = mComposerClient->createSurface(
+        String8("Grandchild surface"), 5, 5,
+        PIXEL_FORMAT_RGBA_8888, 0, child.get());
+    fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+    SurfaceComposerClient::Transaction()
+        .show(child)
+        .setPosition(grandchild, 5, 5)
+        .show(grandchild)
+        .apply(true);
+
+    auto grandchildHandle = grandchild->getHandle();
+
+    // Captures only the grandchild.
+    CaptureLayer::captureScreen(&mCapture, grandchildHandle);
+    mCapture->checkPixel(0, 0, 50, 50, 50);
+    mCapture->checkPixel(4, 4, 50, 50, 50);
+}
+
 }
diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp
index 9851188..967dee5 100644
--- a/services/utils/PriorityDumper.cpp
+++ b/services/utils/PriorityDumper.cpp
@@ -18,41 +18,68 @@
 
 namespace android {
 
-static void getStrippedArgs(Vector<String16>& dest, const Vector<String16>& source,
-                            std::size_t numArgsToStrip) {
-    for (auto it = source.begin() + numArgsToStrip; it != source.end(); it++) {
-        dest.add(*it);
+const char16_t PriorityDumper::PROTO_ARG[] = u"--proto";
+const char16_t PriorityDumper::PRIORITY_ARG[] = u"--dump-priority";
+const char16_t PriorityDumper::PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
+const char16_t PriorityDumper::PRIORITY_ARG_HIGH[] = u"HIGH";
+const char16_t PriorityDumper::PRIORITY_ARG_NORMAL[] = u"NORMAL";
+
+enum class PriorityType { INVALID, CRITICAL, HIGH, NORMAL };
+
+static PriorityType getPriorityType(const String16& arg) {
+    if (arg == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+        return PriorityType::CRITICAL;
+    } else if (arg == PriorityDumper::PRIORITY_ARG_HIGH) {
+        return PriorityType::HIGH;
+    } else if (arg == PriorityDumper::PRIORITY_ARG_NORMAL) {
+        return PriorityType::NORMAL;
     }
+    return PriorityType::INVALID;
 }
 
-status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args) {
+status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args, bool asProto) {
     status_t status;
-    status = dumpCritical(fd, args);
+    status = dumpCritical(fd, args, asProto);
     if (status != OK) return status;
-    status = dumpHigh(fd, args);
+    status = dumpHigh(fd, args, asProto);
     if (status != OK) return status;
-    status = dumpNormal(fd, args);
+    status = dumpNormal(fd, args, asProto);
     if (status != OK) return status;
     return status;
 }
 
 status_t PriorityDumper::priorityDump(int fd, const Vector<String16>& args) {
     status_t status;
-    if (args.size() >= 2 && args[0] == PRIORITY_ARG) {
-        String16 priority = args[1];
-        Vector<String16> strippedArgs;
-        getStrippedArgs(strippedArgs, args, 2);
-        if (priority == PRIORITY_ARG_CRITICAL) {
-            status = dumpCritical(fd, strippedArgs);
-        } else if (priority == PRIORITY_ARG_HIGH) {
-            status = dumpHigh(fd, strippedArgs);
-        } else if (priority == PRIORITY_ARG_NORMAL) {
-            status = dumpNormal(fd, strippedArgs);
+    bool asProto = false;
+    PriorityType priority = PriorityType::INVALID;
+
+    Vector<String16> strippedArgs;
+    for (uint32_t argIndex = 0; argIndex < args.size(); argIndex++) {
+        if (args[argIndex] == PROTO_ARG) {
+            asProto = true;
+        } else if (args[argIndex] == PRIORITY_ARG) {
+            if (argIndex + 1 < args.size()) {
+                argIndex++;
+                priority = getPriorityType(args[argIndex]);
+            }
         } else {
-            status = dumpAll(fd, args);
+            strippedArgs.add(args[argIndex]);
         }
-    } else {
-        status = dumpAll(fd, args);
+    }
+
+    switch (priority) {
+        case PriorityType::CRITICAL:
+            status = dumpCritical(fd, strippedArgs, asProto);
+            break;
+        case PriorityType::HIGH:
+            status = dumpHigh(fd, strippedArgs, asProto);
+            break;
+        case PriorityType::NORMAL:
+            status = dumpNormal(fd, strippedArgs, asProto);
+            break;
+        default:
+            status = dumpAll(fd, strippedArgs, asProto);
+            break;
     }
     return status;
 }
diff --git a/services/utils/include/serviceutils/PriorityDumper.h b/services/utils/include/serviceutils/PriorityDumper.h
index 0319242..d01a102 100644
--- a/services/utils/include/serviceutils/PriorityDumper.h
+++ b/services/utils/include/serviceutils/PriorityDumper.h
@@ -23,34 +23,43 @@
 
 namespace android {
 
-constexpr const char16_t PRIORITY_ARG[] = u"--dump-priority";
-constexpr const char16_t PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
-constexpr const char16_t PRIORITY_ARG_HIGH[] = u"HIGH";
-constexpr const char16_t PRIORITY_ARG_NORMAL[] = u"NORMAL";
-
-// Helper class to split dumps into various priority buckets.
+// Helper class to parse common arguments responsible for splitting dumps into
+// various priority buckets and changing the output format of the dump.
 class PriorityDumper {
 public:
-    // Parses the argument list checking if the first argument is --dump_priority and
-    // the second argument is the priority type (HIGH, CRITICAL or NORMAL). If the
-    // arguments are found, they are stripped and the appropriate PriorityDumper
-    // method is called.
-    // If --dump_priority argument is not passed, all supported sections are dumped.
+    static const char16_t PRIORITY_ARG[];
+    static const char16_t PRIORITY_ARG_CRITICAL[];
+    static const char16_t PRIORITY_ARG_HIGH[];
+    static const char16_t PRIORITY_ARG_NORMAL[];
+    static const char16_t PROTO_ARG[];
+
+    // Parses the argument list searching for --dump_priority with a priority type
+    // (HIGH, CRITICAL or NORMAL) and --proto. Matching arguments are stripped.
+    // If a valid priority type is found, the associated PriorityDumper
+    // method is called otherwise all supported sections are dumped.
+    // If --proto is found, the dumpAsProto flag is set to dump sections in proto
+    // format.
     status_t priorityDump(int fd, const Vector<String16>& args);
 
     // Dumps CRITICAL priority sections.
-    virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+    virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
 
     // Dumps HIGH priority sections.
-    virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+    virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
 
     // Dumps normal priority sections.
-    virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+    virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
 
     // Dumps all sections.
     // This method is called when priorityDump is called without priority
     // arguments. By default, it calls all three dump methods.
-    virtual status_t dumpAll(int fd, const Vector<String16>& args);
+    virtual status_t dumpAll(int fd, const Vector<String16>& args, bool asProto);
     virtual ~PriorityDumper() = default;
 };
 
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
index 79e7340..90cc6de 100644
--- a/services/utils/tests/PriorityDumper_test.cpp
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -32,17 +32,17 @@
 
 class PriorityDumperMock : public PriorityDumper {
 public:
-    MOCK_METHOD2(dumpCritical, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpHigh, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpNormal, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpAll, status_t(int, const Vector<String16>&));
+    MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpAll, status_t(int, const Vector<String16>&, bool));
 };
 
 class DumpAllMock : public PriorityDumper {
 public:
-    MOCK_METHOD2(dumpCritical, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpHigh, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpNormal, status_t(int, const Vector<String16>&));
+    MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
 };
 
 class PriorityDumperTest : public Test {
@@ -61,14 +61,14 @@
 
 TEST_F(PriorityDumperTest, noArgsPassed) {
     Vector<String16> args;
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
 TEST_F(PriorityDumperTest, noPriorityArgsPassed) {
     Vector<String16> args;
     addAll(args, {"bunch", "of", "args"});
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -76,7 +76,7 @@
     Vector<String16> args;
     addAll(args, {"--dump-priority", "CRITICAL"});
     Vector<String16> strippedArgs;
-    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -86,7 +86,17 @@
     Vector<String16> strippedArgs;
     addAll(strippedArgs, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCriticalInMiddle) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "--dump-priority", "CRITICAL", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -96,7 +106,17 @@
     Vector<String16> strippedArgs;
     addAll(strippedArgs, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHighInEnd) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "behind", "--dump-priority", "HIGH"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -106,7 +126,7 @@
     Vector<String16> strippedArgs;
     addAll(strippedArgs, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -114,9 +134,9 @@
     Vector<String16> args;
     addAll(args, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args)));
-    EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args)));
-    EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args), /*asProto=*/false));
+    EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args), /*asProto=*/false));
+    EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args), /*asProto=*/false));
 
     dumpAlldumper_.priorityDump(fd, args);
 }
@@ -124,7 +144,8 @@
 TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) {
     Vector<String16> args;
     addAll(args, {"--dump-priority"});
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
 
     dumper_.priorityDump(fd, args);
 }
@@ -132,7 +153,67 @@
 TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) {
     Vector<String16> args;
     addAll(args, {"--dump-priority", "REALLY_HIGH"});
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArg) {
+    Vector<String16> args;
+    addAll(args, {"--proto"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgs) {
+    Vector<String16> args;
+    addAll(args, {"--proto", "args", "--dump-priority", "NORMAL", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgsInReverseOrder) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NORMAL", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgInMiddle) {
+    Vector<String16> args;
+    addAll(args, {"--unknown", "args", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgAtEnd) {
+    Vector<String16> args;
+    addAll(args, {"--unknown", "args", "args", "left", "behind", "--proto"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithInvalidPriorityType) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NOT_SO_HIGH", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
 
     dumper_.priorityDump(fd, args);
 }
\ No newline at end of file