Merge "Use -Werror in frameworks/native/libs/gui and ui" am: c4ebf5bbab am: 3a566dd1e1 am: 14ac77cd1e
am: 6d560a52fc

Change-Id: I6b612a1fff0da31b16c1121d0f3d08abf407336c
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 9dbbb77..07a6adb 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -130,6 +130,14 @@
         { REQ,      "events/irq/enable" },
         { OPT,      "events/ipi/enable" },
     } },
+    { "irqoff",     "IRQ-disabled code section tracing", 0, {
+        { REQ,      "events/preemptirq/irq_enable/enable" },
+        { REQ,      "events/preemptirq/irq_disable/enable" },
+    } },
+    { "preemptoff", "Preempt-disabled code section tracing", 0, {
+        { REQ,      "events/preemptirq/preempt_enable/enable" },
+        { REQ,      "events/preemptirq/preempt_disable/enable" },
+    } },
     { "i2c",        "I2C Events",   0, {
         { REQ,      "events/i2c/enable" },
         { REQ,      "events/i2c/i2c_read/enable" },
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index b995b80..dee89cf 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -56,8 +56,20 @@
 - `description.txt`: whose value is a multi-line, detailed description of the problem.
 
 ## Android O versions
-On _Android O (OhMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made:
-- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-1`).
+On _Android O (Oreo)_, the following changes were made:
+- The ANR traces are added to the `FS` folder, typically under `FS/data/anr` (version `2.0-dev-split-anr`).
+
+## Android P versions
+On _Android P (PleaseMightyAndroidWhatsYourNextReleaseName?)_, the following changes were made:
+- Dumpsys sections are dumped by priority (version `2.0-dev-priority-dumps`).
+  Supported priorities can be specified when registering framework services. Section headers are
+  changed to contain priority info.
+  `DUMPSYS` -> `DUMPSYS CRITICAL/HIGH/NORMAL`
+  `DUMP OF SERVICE <servicename>` -> `DUMP OF SERVICE CRITICAL/HIGH/NORMAL <servicename>`
+  Supported Priorities:
+    - CRITICAL - services that must dump first, and fast (under 100ms). Ex: cpuinfo.
+    - HIGH - services that also must dump first, but can take longer (under 250ms) to dump. Ex: meminfo.
+    - NORMAL - services that have no rush to dump and can take a long time (under 10s).
 
 ## Intermediate versions
 During development, the versions will be suffixed with _-devX_ or
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 79397d2..b1a03fa 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1038,6 +1038,40 @@
     RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
 }
 
+// Runs dumpsys on services that must dump first and and will take less than 100ms to dump.
+static void RunDumpsysCritical() {
+    if (ds.CurrentVersionSupportsPriorityDumps()) {
+        RunDumpsys("DUMPSYS CRITICAL", {"--priority", "CRITICAL"},
+                   CommandOptions::WithTimeout(5).DropRoot().Build());
+    } else {
+        RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
+                   CommandOptions::WithTimeout(90).DropRoot().Build());
+        RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
+                   CommandOptions::WithTimeout(10).DropRoot().Build());
+    }
+}
+
+// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
+static void RunDumpsysHigh() {
+    if (ds.CurrentVersionSupportsPriorityDumps()) {
+        RunDumpsys("DUMPSYS HIGH", {"--priority", "HIGH"},
+                   CommandOptions::WithTimeout(20).DropRoot().Build());
+    } else {
+        RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"});
+    }
+}
+
+// Runs dumpsys on services that must dump but can take up to 10s to dump.
+static void RunDumpsysNormal() {
+    if (ds.CurrentVersionSupportsPriorityDumps()) {
+        RunDumpsys("DUMPSYS NORMAL", {"--priority", "NORMAL"},
+                   CommandOptions::WithTimeout(90).DropRoot().Build());
+    } else {
+        RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"},
+                   CommandOptions::WithTimeout(90).Build(), 10);
+    }
+}
+
 static void dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
@@ -1062,7 +1096,7 @@
     DumpFile("KERNEL SYNC", "/d/sync");
 
     RunCommand("PROCESSES AND THREADS",
-               {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
+               {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
     RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
 
     if (ds.IsZipping()) {
@@ -1128,15 +1162,14 @@
     RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
     RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
 
-    RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
-               CommandOptions::WithTimeout(10).Build());
+    RunDumpsysHigh();
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
     RunCommand("VOLD DUMP", {"vdc", "dump"});
     RunCommand("SECURE CONTAINERS", {"vdc", "asec", "list"});
 
-    RunCommand("STORAGED TASKIOINFO", {"storaged", "-u"}, CommandOptions::WithTimeout(10).Build());
+    RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
 
     RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
 
@@ -1182,8 +1215,7 @@
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"}, CommandOptions::WithTimeout(90).Build(),
-               10);
+    RunDumpsysNormal();
 
     printf("========================================================\n");
     printf("== Checkins\n");
@@ -1624,10 +1656,12 @@
         ds.version_ = VERSION_CURRENT;
     }
 
-    if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
-        MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
-               ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
-               VERSION_SPLIT_ANR.c_str());
+    if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR &&
+        ds.version_ != VERSION_PRIORITY_DUMPS) {
+        MYLOGE(
+            "invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s', '%s')\n",
+            ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
+            VERSION_SPLIT_ANR.c_str(), VERSION_PRIORITY_DUMPS.c_str());
         exit(1);
     }
 
@@ -1818,10 +1852,7 @@
 
         // Invoking the following dumpsys calls before dump_traces() to try and
         // keep the system stats as close to its initial state as possible.
-        RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
-                   CommandOptions::WithTimeout(90).DropRoot().Build());
-        RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
-                   CommandOptions::WithTimeout(10).DropRoot().Build());
+        RunDumpsysCritical();
 
         // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
         dump_raft();
@@ -1851,6 +1882,9 @@
         RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"},
                    CommandOptions::WithTimeout(10).Build());
 
+        // Run iotop as root to show top 100 IO threads
+        RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
+
         if (!DropRootUser()) {
             return -1;
         }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7757c1e..1bfafba 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -149,9 +149,15 @@
 
 /*
  * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version
- * will be bumped to 2.0-dev-1.
+ * will be bumped to 2.0.
  */
-static std::string VERSION_SPLIT_ANR = "2.0-dev-1";
+static std::string VERSION_SPLIT_ANR = "2.0-dev-split-anr";
+
+/*
+ * Temporary version that adds priority based dumps. Once tools support it, the current version
+ * will be bumped to 2.0.
+ */
+static std::string VERSION_PRIORITY_DUMPS = "2.0-dev-priority-dumps";
 
 /*
  * "Alias" for the current version.
@@ -266,6 +272,9 @@
     /* Gets the path of a bugreport file with the given suffix. */
     std::string GetPath(const std::string& suffix) const;
 
+    /* Returns true if the current version supports priority dump feature. */
+    bool CurrentVersionSupportsPriorityDumps() const;
+
     // TODO: initialize fields on constructor
 
     // dumpstate id - unique after each device reboot.
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 93f4c22..c2c9071 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -257,6 +257,10 @@
                                        name_.c_str(), suffix.c_str());
 }
 
+bool Dumpstate::CurrentVersionSupportsPriorityDumps() const {
+    return (version_ == VERSION_PRIORITY_DUMPS);
+}
+
 void Dumpstate::SetProgress(std::unique_ptr<Progress> progress) {
     progress_ = std::move(progress);
 }
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 3476964..f68b862 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -17,6 +17,10 @@
         "libbinder",
     ],
 
+    static_libs: [
+        "libserviceutils",
+    ],
+
     clang: true,
 }
 
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 3227749..239a2d5 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -25,6 +25,7 @@
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/TextOutput.h>
+#include <serviceutils/PriorityDumper.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
 
@@ -53,13 +54,16 @@
 
 static void usage() {
     fprintf(stderr,
-        "usage: dumpsys\n"
+            "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
+            "SERVICE [ARGS]]\n"
             "         --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"
+            "         --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"
             "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
 }
@@ -73,18 +77,35 @@
     return false;
 }
 
+static bool ConvertPriorityTypeToBitmask(String16& type, int& bitmask) {
+    if (type == PRIORITY_ARG_CRITICAL) {
+        bitmask = IServiceManager::DUMP_PRIORITY_CRITICAL;
+        return true;
+    }
+    if (type == PRIORITY_ARG_HIGH) {
+        bitmask = IServiceManager::DUMP_PRIORITY_HIGH;
+        return true;
+    }
+    if (type == PRIORITY_ARG_NORMAL) {
+        bitmask = IServiceManager::DUMP_PRIORITY_NORMAL;
+        return true;
+    }
+    return false;
+}
+
 int Dumpsys::main(int argc, char* const argv[]) {
     Vector<String16> services;
     Vector<String16> args;
+    String16 priorityType;
     Vector<String16> skippedServices;
     bool showListOnly = false;
     bool skipServices = false;
     int timeoutArg = 10;
-    static struct option longOptions[] = {
-        {"skip", no_argument, 0,  0 },
-        {"help", no_argument, 0,  0 },
-        {     0,           0, 0,  0 }
-    };
+    int dumpPriority = IServiceManager::DUMP_PRIORITY_ALL;
+    static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+                                          {"skip", no_argument, 0, 0},
+                                          {"help", no_argument, 0, 0},
+                                          {0, 0, 0, 0}};
 
     // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
     // happens on test cases).
@@ -106,6 +127,13 @@
             } 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)) {
+                    fprintf(stderr, "\n");
+                    usage();
+                    return -1;
+                }
             }
             break;
 
@@ -151,9 +179,14 @@
 
     if (services.empty() || showListOnly) {
         // gets all services
-        services = sm_->listServices();
+        services = sm_->listServices(dumpPriority);
         services.sort(sort_func);
-        args.add(String16("-a"));
+        if (dumpPriority != IServiceManager::DUMP_PRIORITY_ALL) {
+            args.insertAt(String16(PRIORITY_ARG), 0);
+            args.insertAt(priorityType, 1);
+        } else {
+            args.add(String16("-a"));
+        }
     }
 
     const size_t N = services.size();
@@ -197,7 +230,11 @@
             if (N > 1) {
                 aout << "------------------------------------------------------------"
                         "-------------------" << endl;
-                aout << "DUMP OF SERVICE " << service_name << ":" << endl;
+                if (dumpPriority == IServiceManager::DUMP_PRIORITY_ALL) {
+                    aout << "DUMP OF SERVICE " << service_name << ":" << endl;
+                } else {
+                    aout << "DUMP OF SERVICE " << priorityType << " " << service_name << ":" << endl;
+                }
             }
 
             // dump blocks until completion, so spawn a thread..
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 16fefe6..9fe4572 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -50,8 +50,8 @@
   public:
     MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
     MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
-    MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool));
-    MOCK_METHOD0(listServices, Vector<String16>());
+    MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
+    MOCK_METHOD1(listServices, Vector<String16>(int));
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
@@ -131,7 +131,16 @@
         for (auto& service : services) {
             services16.add(String16(service.c_str()));
         }
-        EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
+        EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_PRIORITY_ALL))
+            .WillRepeatedly(Return(services16));
+    }
+
+    void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpPriority) {
+        Vector<String16> services16;
+        for (auto& service : services) {
+            services16.add(String16(service.c_str()));
+        }
+        EXPECT_CALL(sm_, listServices(dumpPriority)).WillRepeatedly(Return(services16));
     }
 
     sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
@@ -179,7 +188,10 @@
     }
 
     void AssertRunningServices(const std::vector<std::string>& services) {
-        std::string expected("Currently running services:\n");
+        std::string expected;
+        if (services.size() > 1) {
+            expected.append("Currently running services:\n");
+        }
         for (const std::string& service : services) {
             expected.append("  ").append(service).append("\n");
         }
@@ -236,6 +248,26 @@
     AssertNotDumped({"Valet"});
 }
 
+// Tests 'dumpsys -l --priority HIGH'
+TEST_F(DumpsysTest, ListAllServicesWithPriority) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_PRIORITY_HIGH);
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"-l", "--priority", "HIGH"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+}
+
+// Tests 'dumpsys -l --priority HIGH' with and empty list
+TEST_F(DumpsysTest, ListEmptyServicesWithPriority) {
+    ExpectListServicesWithPriority({}, IServiceManager::DUMP_PRIORITY_HIGH);
+
+    CallMain({"-l", "--priority", "HIGH"});
+
+    AssertRunningServices({});
+}
+
 // Tests 'dumpsys service_name' on a service is running
 TEST_F(DumpsysTest, DumpRunningService) {
     ExpectDump("Valet", "Here's your car");
@@ -300,3 +332,65 @@
     AssertNotDumped("dump3");
     AssertNotDumped("dump5");
 }
+
+// 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);
+    ExpectDump("running1", "dump1");
+    ExpectCheckService("stopped2", false);
+    ExpectDump("skipped3", "dump3");
+    ExpectDump("running4", "dump4");
+    ExpectDump("skipped5", "dump5");
+
+    CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"});
+
+    AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
+    AssertDumped("running1", "dump1");
+    AssertDumped("running4", "dump4");
+    AssertStopped("stopped2");
+    AssertNotDumped("dump3");
+    AssertNotDumped("dump5");
+}
+
+// Tests 'dumpsys --priority CRITICAL'
+TEST_F(DumpsysTest, DumpWithPriorityCritical) {
+    ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"},
+                                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+    ExpectDump("runningcritical1", "dump1");
+    ExpectDump("runningcritical2", "dump2");
+
+    CallMain({"--priority", "CRITICAL"});
+
+    AssertRunningServices({"runningcritical1", "runningcritical2"});
+    AssertDumped("runningcritical1", "dump1");
+    AssertDumped("runningcritical2", "dump2");
+}
+
+// Tests 'dumpsys --priority HIGH'
+TEST_F(DumpsysTest, DumpWithPriorityHigh) {
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+                                   IServiceManager::DUMP_PRIORITY_HIGH);
+    ExpectDump("runninghigh1", "dump1");
+    ExpectDump("runninghigh2", "dump2");
+
+    CallMain({"--priority", "HIGH"});
+
+    AssertRunningServices({"runninghigh1", "runninghigh2"});
+    AssertDumped("runninghigh1", "dump1");
+    AssertDumped("runninghigh2", "dump2");
+}
+
+// Tests 'dumpsys --priority NORMAL'
+TEST_F(DumpsysTest, DumpWithPriorityNormal) {
+    ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"},
+                                   IServiceManager::DUMP_PRIORITY_NORMAL);
+    ExpectDump("runningnormal1", "dump1");
+    ExpectDump("runningnormal2", "dump2");
+
+    CallMain({"--priority", "NORMAL"});
+
+    AssertRunningServices({"runningnormal1", "runningnormal2"});
+    AssertDumped("runningnormal1", "dump1");
+    AssertDumped("runningnormal2", "dump2");
+}
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index dfc3e58..d5b3372 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -269,24 +269,10 @@
         return false;
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    err = sc->setLayer(0x7FFFFFFF);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
-        return false;
-    }
-    err = sc->setMatrix(scale, 0.0f, 0.0f, scale);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err);
-        return false;
-    }
-
-    err = sc->show();
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
-        return false;
-    }
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
+            .setMatrix(sc, scale, 0.0f, 0.0f, scale)
+            .show(sc)
+            .apply();
 
     sp<ANativeWindow> anw = sc->getSurface();
     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 33db6db..56470d6 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -4,6 +4,7 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wextra",
     ],
     srcs: [
         "CacheItem.cpp",
@@ -25,6 +26,17 @@
     ],
 
     clang: true,
+
+    tidy: true,
+    tidy_checks: [
+        "-*",
+        "clang-analyzer-security*",
+        "cert-*",
+        "-cert-err58-cpp",
+    ],
+    tidy_flags: [
+        "-warnings-as-errors=clang-analyzer-security*,cert-*"
+    ],
 }
 
 //
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4a93b1f..4246536 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -714,6 +714,9 @@
                     // Ignore all other GID transitions, since they're kinda shady
                     LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
                             << " instead of " << expected;
+                    if (!(flags & FLAG_FORCE)) {
+                        fts_set(fts, p, FTS_SKIP);
+                    }
                 }
             }
         }
@@ -1866,7 +1869,7 @@
     char boot_marker_path[PKG_PATH_MAX];
     sprintf(boot_marker_path,
           "%s/%s/%s/.booting",
-          android_data_dir.path,
+          android_data_dir.c_str(),
           DALVIK_CACHE,
           instruction_set);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 6f7ab6b..4bb8ebe 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -41,6 +41,7 @@
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
+#include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
 #include "utils.h"
@@ -156,7 +157,7 @@
   int count = 0;
   char buf[kPropertyValueMax];
 
-  strncpy(buf, str, sizeof(buf));
+  strlcpy(buf, str, sizeof(buf));
   char *pBuf = buf;
 
   while(strtok_r(pBuf, " ", &ctx) != NULL) {
@@ -333,7 +334,8 @@
 
     bool have_dex2oat_compiler_filter_flag = false;
     if (skip_compilation) {
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+        strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
+                sizeof(dex2oat_compiler_filter_arg));
         have_dex2oat_compiler_filter_flag = true;
         have_dex2oat_relocation_skip_flag = true;
     } else if (compiler_filter != nullptr) {
@@ -955,14 +957,6 @@
     return replace_file_extension(oat_path, ".vdex");
 }
 
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
-    if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
-        return false;
-    }
-    strcat(file_name, extension);
-    return true;
-}
-
 static int open_output_file(const char* file_name, bool recreate, int permissions) {
     int flags = O_RDWR | O_CREAT;
     if (recreate) {
@@ -1198,21 +1192,16 @@
     if (!ShouldUseSwapFileForDexopt()) {
         return invalid_unique_fd();
     }
-    // Make sure there really is enough space.
-    char swap_file_name[PKG_PATH_MAX];
-    strcpy(swap_file_name, out_oat_path);
-    if (!add_extension_to_file_name(swap_file_name, ".swap")) {
-        return invalid_unique_fd();
-    }
+    auto swap_file_name = std::string(out_oat_path) + ".swap";
     unique_fd swap_fd(open_output_file(
-            swap_file_name, /*recreate*/true, /*permissions*/0600));
+            swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
     if (swap_fd.get() < 0) {
         // Could not create swap file. Optimistically go on and hope that we can compile
         // without it.
-        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+        ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name.c_str());
     } else {
         // Immediately unlink. We don't really want to hit flash.
-        if (unlink(swap_file_name) < 0) {
+        if (unlink(swap_file_name.c_str()) < 0) {
             PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
         }
     }
@@ -1376,7 +1365,8 @@
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
 static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set,
-        const std::string& compiler_filter, bool profile_was_updated, bool downgrade) {
+        const std::string& compiler_filter, bool profile_was_updated, bool downgrade,
+        const char* class_loader_context) {
     const char* dexoptanalyzer_bin =
             is_debug_runtime()
                     ? "/system/bin/dexoptanalyzerd"
@@ -1394,11 +1384,16 @@
     std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
     const char* assume_profile_changed = "--assume-profile-changed";
     const char* downgrade_flag = "--downgrade";
+    std::string class_loader_context_arg = "--class-loader-context=";
+    if (class_loader_context != nullptr) {
+        class_loader_context_arg += class_loader_context;
+    }
 
     // program name, dex file, isa, filter, the final NULL
     const int argc = 5 +
         (profile_was_updated ? 1 : 0) +
-        (downgrade ? 1 : 0);
+        (downgrade ? 1 : 0) +
+        (class_loader_context != nullptr ? 1 : 0);
     const char* argv[argc];
     int i = 0;
     argv[i++] = dexoptanalyzer_bin;
@@ -1411,6 +1406,9 @@
     if (downgrade) {
         argv[i++] = downgrade_flag;
     }
+    if (class_loader_context != nullptr) {
+        argv[i++] = class_loader_context;
+    }
     argv[i] = NULL;
 
     execv(dexoptanalyzer_bin, (char * const *)argv);
@@ -1491,7 +1489,8 @@
 static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, std::string* dex_path_out, bool downgrade) {
+        std::string* oat_dir_out, std::string* dex_path_out, bool downgrade,
+        const char* class_loader_context) {
     int storage_flag;
 
     if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
@@ -1561,7 +1560,7 @@
         drop_capabilities(uid);
         // Run dexoptanalyzer to get dexopt_needed code.
         exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated,
-                            downgrade);
+                            downgrade, class_loader_context);
         exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
     }
 
@@ -1617,8 +1616,7 @@
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                &dex_real_path,
-                downgrade)) {
+                &dex_real_path, downgrade, class_loader_context)) {
             oat_dir = oat_dir_str.c_str();
             dex_path = dex_real_path.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
@@ -2040,5 +2038,98 @@
     return return_value_oat && return_value_art && return_value_vdex;
 }
 
+static bool is_absolute_path(const std::string& path) {
+    if (path.find('/') != 0 || path.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid absolute path " << path;
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static bool is_valid_instruction_set(const std::string& instruction_set) {
+    // TODO: add explicit whitelisting of instruction sets
+    if (instruction_set.find('/') != std::string::npos) {
+        LOG(ERROR) << "Invalid instruction set " << instruction_set;
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+        const char *apk_path, const char *instruction_set) {
+    std::string oat_dir_ = oat_dir;
+    std::string apk_path_ = apk_path;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(oat_dir_)) return false;
+    if (!is_absolute_path(apk_path_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    std::string::size_type end = apk_path_.rfind('.');
+    std::string::size_type start = apk_path_.rfind('/', end);
+    if (end == std::string::npos || start == std::string::npos) {
+        LOG(ERROR) << "Invalid apk_path " << apk_path_;
+        return false;
+    }
+
+    std::string res_ = oat_dir_ + '/' + instruction_set + '/'
+            + apk_path_.substr(start + 1, end - start - 1) + ".odex";
+    const char* res = res_.c_str();
+    if (strlen(res) >= PKG_PATH_MAX) {
+        LOG(ERROR) << "Result too large";
+        return false;
+    } else {
+        strlcpy(path, res, PKG_PATH_MAX);
+        return true;
+    }
+}
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    std::string apk_path_ = apk_path;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(apk_path_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    std::string::size_type end = apk_path_.rfind('.');
+    std::string::size_type start = apk_path_.rfind('/', end);
+    if (end == std::string::npos || start == std::string::npos) {
+        LOG(ERROR) << "Invalid apk_path " << apk_path_;
+        return false;
+    }
+
+    std::string oat_dir = apk_path_.substr(0, start + 1) + "oat";
+    return calculate_oat_file_path_default(path, oat_dir.c_str(), apk_path, instruction_set);
+}
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+        const char *instruction_set) {
+    std::string src_ = src;
+    std::string instruction_set_ = instruction_set;
+
+    if (!is_absolute_path(src_)) return false;
+    if (!is_valid_instruction_set(instruction_set_)) return false;
+
+    for (auto it = src_.begin() + 1; it < src_.end(); ++it) {
+        if (*it == '/') {
+            *it = '@';
+        }
+    }
+
+    std::string res_ = android_data_dir + DALVIK_CACHE + '/' + instruction_set_ + src_
+            + DALVIK_CACHE_POSTFIX;
+    const char* res = res_.c_str();
+    if (strlen(res) >= PKG_PATH_MAX) {
+        LOG(ERROR) << "Result too large";
+        return false;
+    } else {
+        strlcpy(path, res, PKG_PATH_MAX);
+        return true;
+    }
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 23446da..1f41e67 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -17,6 +17,8 @@
 #ifndef DEXOPT_H_
 #define DEXOPT_H_
 
+#include "installd_constants.h"
+
 #include <sys/types.h>
 
 #include <cutils/multiuser.h>
@@ -66,6 +68,15 @@
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
         bool downgrade);
 
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+        const char *apk_path, const char *instruction_set);
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set);
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+        const char *instruction_set);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index edcdb6a..b3a6daf 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -16,15 +16,15 @@
 
 #define LOG_TAG "installd"
 
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log.h>              // TODO: Move everything to base::logging.
-
 #include <globals.h>
 #include <installd_constants.h>
 #include <utils.h>
 
+#include <android-base/logging.h>
+
+#include <stdlib.h>
+#include <string.h>
+
 namespace android {
 namespace installd {
 
@@ -44,106 +44,78 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
-/* Directory records that are used in execution of commands. */
-dir_rec_t android_app_dir;
-dir_rec_t android_app_ephemeral_dir;
-dir_rec_t android_app_lib_dir;
-dir_rec_t android_app_private_dir;
-dir_rec_t android_asec_dir;
-dir_rec_t android_data_dir;
-dir_rec_t android_media_dir;
-dir_rec_t android_mnt_expand_dir;
-dir_rec_t android_profiles_dir;
+std::string android_app_dir;
+std::string android_app_ephemeral_dir;
+std::string android_app_lib_dir;
+std::string android_app_private_dir;
+std::string android_asec_dir;
+std::string android_data_dir;
+std::string android_media_dir;
+std::string android_mnt_expand_dir;
+std::string android_profiles_dir;
+std::string android_root_dir;
 
-dir_rec_array_t android_system_dirs;
+std::vector<std::string> android_system_dirs;
 
-/**
- * Initialize all the global variables that are used elsewhere. Returns 0 upon
- * success and -1 on error.
- */
-void free_globals() {
-    size_t i;
-
-    for (i = 0; i < android_system_dirs.count; i++) {
-        if (android_system_dirs.dirs[i].path != NULL) {
-            free(android_system_dirs.dirs[i].path);
-        }
+bool init_globals_from_data_and_root() {
+    const char* data_path = getenv("ANDROID_DATA");
+    if (data_path == nullptr) {
+        LOG(ERROR) << "Could not find ANDROID_DATA";
+        return false;
     }
+    const char* root_path = getenv("ANDROID_ROOT");
+    if (root_path == nullptr) {
+        LOG(ERROR) << "Could not find ANDROID_ROOT";
+        return false;
+    }
+    return init_globals_from_data_and_root(data_path, root_path);
+}
 
-    free(android_system_dirs.dirs);
+static std::string ensure_trailing_slash(const std::string& path) {
+    if (path.rfind('/') != path.size() - 1) {
+        return path + '/';
+    } else {
+        return path;
+    }
 }
 
 bool init_globals_from_data_and_root(const char* data, const char* root) {
     // Get the android data directory.
-    if (get_path_from_string(&android_data_dir, data) < 0) {
-        return false;
-    }
+    android_data_dir = ensure_trailing_slash(data);
+
+    // Get the android root directory.
+    android_root_dir = ensure_trailing_slash(root);
 
     // Get the android app directory.
-    if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_dir = android_data_dir + APP_SUBDIR;
 
     // Get the android protected app directory.
-    if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_private_dir = android_data_dir + PRIVATE_APP_SUBDIR;
 
     // Get the android ephemeral app directory.
-    if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_ephemeral_dir = android_data_dir + EPHEMERAL_APP_SUBDIR;
 
     // Get the android app native library directory.
-    if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
-        return false;
-    }
+    android_app_lib_dir = android_data_dir + APP_LIB_SUBDIR;
 
     // Get the sd-card ASEC mount point.
-    if (get_path_from_env(&android_asec_dir, ASEC_MOUNTPOINT_ENV_NAME) < 0) {
-        return false;
-    }
+    android_asec_dir = ensure_trailing_slash(getenv(ASEC_MOUNTPOINT_ENV_NAME));
 
     // Get the android media directory.
-    if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
-        return false;
-    }
+    android_media_dir = android_data_dir + MEDIA_SUBDIR;
 
     // Get the android external app directory.
-    if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
-        return false;
-    }
+    android_mnt_expand_dir = "/mnt/expand/";
 
     // Get the android profiles directory.
-    if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) {
-        return false;
-    }
+    android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
     // Take note of the system and vendor directories.
-    android_system_dirs.count = 4;
-
-    android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
-    if (android_system_dirs.dirs == NULL) {
-        ALOGE("Couldn't allocate array for dirs; aborting\n");
-        return false;
-    }
-
-    dir_rec_t android_root_dir;
-    if (get_path_from_string(&android_root_dir, root) < 0) {
-        return false;
-    }
-
-    android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
-    android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
-
-    android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
-    android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
-
-    android_system_dirs.dirs[2].path = strdup("/vendor/app/");
-    android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);
-
-    android_system_dirs.dirs[3].path = strdup("/oem/app/");
-    android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
+    android_system_dirs.clear();
+    android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
+    android_system_dirs.push_back(android_root_dir + PRIV_APP_SUBDIR);
+    android_system_dirs.push_back("/vendor/app/");
+    android_system_dirs.push_back("/oem/app/");
 
     return true;
 }
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index c90beec..633e33b 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -19,40 +19,29 @@
 #define GLOBALS_H_
 
 #include <inttypes.h>
+#include <string>
+#include <vector>
 
 namespace android {
 namespace installd {
 
-/* constants */
-
 // Name of the environment variable that contains the asec mountpoint.
 static constexpr const char* ASEC_MOUNTPOINT_ENV_NAME = "ASEC_MOUNTPOINT";
 
-/* data structures */
+extern std::string android_app_dir;
+extern std::string android_app_ephemeral_dir;
+extern std::string android_app_lib_dir;
+extern std::string android_app_private_dir;
+extern std::string android_asec_dir;
+extern std::string android_data_dir;
+extern std::string android_media_dir;
+extern std::string android_mnt_expand_dir;
+extern std::string android_profiles_dir;
+extern std::string android_root_dir;
 
-struct dir_rec_t {
-    char* path;
-    size_t len;
-};
+extern std::vector<std::string> android_system_dirs;
 
-struct dir_rec_array_t {
-    size_t count;
-    dir_rec_t* dirs;
-};
-
-extern dir_rec_t android_app_dir;
-extern dir_rec_t android_app_ephemeral_dir;
-extern dir_rec_t android_app_lib_dir;
-extern dir_rec_t android_app_private_dir;
-extern dir_rec_t android_asec_dir;
-extern dir_rec_t android_data_dir;
-extern dir_rec_t android_media_dir;
-extern dir_rec_t android_mnt_expand_dir;
-extern dir_rec_t android_profiles_dir;
-
-extern dir_rec_array_t android_system_dirs;
-
-void free_globals();
+bool init_globals_from_data_and_root();
 bool init_globals_from_data_and_root(const char* data, const char* root);
 
 }  // namespace installd
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 35936a2..95ed2ff 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -30,6 +30,7 @@
 #include <private/android_filesystem_config.h>
 
 #include "InstalldNativeService.h"
+#include "dexopt.h"
 #include "globals.h"
 #include "installd_constants.h"
 #include "installd_deps.h"  // Need to fill in requirements of commands.
@@ -50,133 +51,22 @@
     return property_get(key, value, default_value);
 }
 
-// Compute the output path of
-bool calculate_oat_file_path(char path[PKG_PATH_MAX],
-                             const char *oat_dir,
-                             const char *apk_path,
-                             const char *instruction_set) {
-    const char *file_name_start;
-    const char *file_name_end;
-
-    file_name_start = strrchr(apk_path, '/');
-    if (file_name_start == NULL) {
-        SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
-        return false;
-    }
-    file_name_end = strrchr(apk_path, '.');
-    if (file_name_end < file_name_start) {
-        SLOGE("apk_path '%s' has no extension\n", apk_path);
-        return false;
-    }
-
-    // Calculate file_name
-    int file_name_len = file_name_end - file_name_start - 1;
-    char file_name[file_name_len + 1];
-    memcpy(file_name, file_name_start + 1, file_name_len);
-    file_name[file_name_len] = '\0';
-
-    // <apk_parent_dir>/oat/<isa>/<file_name>.odex
-    snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
-    return true;
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+        const char *instruction_set) {
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
 }
 
-/*
- * Computes the odex file for the given apk_path and instruction_set.
- * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
- *
- * Returns false if it failed to determine the odex file path.
- */
-bool calculate_odex_file_path(char path[PKG_PATH_MAX],
-                              const char *apk_path,
-                              const char *instruction_set) {
-    if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
-            + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
-        SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
-        return false;
-    }
-
-    strcpy(path, apk_path);
-    char *end = strrchr(path, '/');
-    if (end == NULL) {
-        SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
-        return false;
-    }
-    const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
-
-    strcpy(end + 1, "oat/");       // path = /system/framework/oat/\0
-    strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
-    strcat(path, apk_end);         // path = /system/framework/oat/<isa>/whatever.jar\0
-    end = strrchr(path, '.');
-    if (end == NULL) {
-        SLOGE("apk_path '%s' has no extension.\n", apk_path);
-        return false;
-    }
-    strcpy(end + 1, "odex");
-    return true;
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
 }
 
-bool create_cache_path(char path[PKG_PATH_MAX],
-                       const char *src,
-                       const char *instruction_set) {
-    /* demand that we are an absolute path */
-    if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
-        return false;
-    }
-
-    size_t srclen = strlen(src);
-
-    if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
-        return false;
-    }
-
-    size_t dstlen =
-        android_data_dir.len +
-        strlen(DALVIK_CACHE) +
-        1 +
-        strlen(instruction_set) +
-        srclen +
-        strlen(DALVIK_CACHE_POSTFIX) + 2;
-
-    if (dstlen > PKG_PATH_MAX) {
-        return false;
-    }
-
-    sprintf(path,"%s%s/%s/%s",
-            android_data_dir.path,
-            DALVIK_CACHE,
-            instruction_set,
-            src + 1 /* skip the leading / */);
-
-    char* tmp =
-            path +
-            android_data_dir.len +
-            strlen(DALVIK_CACHE) +
-            1 +
-            strlen(instruction_set) + 1;
-
-    for(; *tmp; tmp++) {
-        if (*tmp == '/') {
-            *tmp = '@';
-        }
-    }
-
-    strcat(path, DALVIK_CACHE_POSTFIX);
-    return true;
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
 }
 
 static bool initialize_globals() {
-    const char* data_path = getenv("ANDROID_DATA");
-    if (data_path == nullptr) {
-        SLOGE("Could not find ANDROID_DATA");
-        return false;
-    }
-    const char* root_path = getenv("ANDROID_ROOT");
-    if (root_path == nullptr) {
-        SLOGE("Could not find ANDROID_ROOT");
-        return false;
-    }
-
-    return init_globals_from_data_and_root(data_path, root_path);
+    return init_globals_from_data_and_root();
 }
 
 static int initialize_directories() {
@@ -184,7 +74,7 @@
 
     // Read current filesystem layout version to handle upgrade paths
     char version_path[PATH_MAX];
-    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
+    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
 
     int oldVersion;
     if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
@@ -206,7 +96,7 @@
         SLOGD("Upgrading to /data/misc/user directories");
 
         char misc_dir[PATH_MAX];
-        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
+        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());
 
         char keychain_added_dir[PATH_MAX];
         snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
@@ -227,7 +117,7 @@
                     if ((name[1] == '.') && (name[2] == 0)) continue;
                 }
 
-                uint32_t user_id = atoi(name);
+                uint32_t user_id = std::stoi(name);
 
                 // /data/misc/user/<user_id>
                 if (ensure_config_user_dirs(user_id) == -1) {
@@ -281,7 +171,7 @@
     return res;
 }
 
-static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
     va_list ap;
     int priority;
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 09e1a00..e0d23da 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -146,14 +146,13 @@
                 return 0;
             }
             // Copy in the default value.
-            strncpy(value, default_value, kPropertyValueMax - 1);
+            strlcpy(value, default_value, kPropertyValueMax - 1);
             value[kPropertyValueMax - 1] = 0;
             return strlen(default_value);// TODO: Need to truncate?
         }
-        size_t size = std::min(kPropertyValueMax - 1, prop_value->length());
-        strncpy(value, prop_value->data(), size);
-        value[size] = 0;
-        return static_cast<int>(size);
+        size_t size = std::min(kPropertyValueMax - 1, prop_value->length()) + 1;
+        strlcpy(value, prop_value->data(), size);
+        return static_cast<int>(size - 1);
     }
 
     std::string GetOTADataDirectory() const {
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index c6ebb24..89c11aa 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -6,13 +6,13 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: [
         "libbase",
-        "liblog",
         "libutils",
         "libcutils",
     ],
     static_libs: [
-        "libinstalld",
         "libdiskusage",
+        "libinstalld",
+        "liblog",
     ],
 }
 
@@ -25,14 +25,14 @@
         "libbase",
         "libbinder",
         "libcutils",
-        "liblog",
-        "liblogwrap",
         "libselinux",
         "libutils",
     ],
     static_libs: [
-        "libinstalld",
         "libdiskusage",
+        "libinstalld",
+        "liblog",
+        "liblogwrap",
     ],
 }
 
@@ -45,13 +45,13 @@
         "libbase",
         "libbinder",
         "libcutils",
-        "liblog",
-        "liblogwrap",
         "libselinux",
         "libutils",
     ],
     static_libs: [
-        "libinstalld",
         "libdiskusage",
+        "libinstalld",
+        "liblog",
+        "liblogwrap",
     ],
 }
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 34818f6..ca812bd 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -25,6 +25,7 @@
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
+#include "dexopt.h"
 #include "globals.h"
 #include "utils.h"
 
@@ -41,25 +42,18 @@
     return property_get(key, value, default_value);
 }
 
-bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
-        const char *oat_dir ATTRIBUTE_UNUSED,
-        const char *apk_path ATTRIBUTE_UNUSED,
-        const char *instruction_set ATTRIBUTE_UNUSED) {
-    return false;
-}
-
-bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
-        const char *apk_path ATTRIBUTE_UNUSED,
-        const char *instruction_set ATTRIBUTE_UNUSED) {
-    return false;
-}
-
-bool create_cache_path(char path[PKG_PATH_MAX],
-        const char *src,
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
         const char *instruction_set) {
-    // Not really a valid path but it's good enough for testing.
-    sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src);
-    return true;
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+        const char *instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
 }
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -102,6 +96,8 @@
         testUuid = std::make_unique<std::string>();
         *testUuid = std::string(kTestUuid);
         system("mkdir -p /data/local/tmp/user/0");
+
+        init_globals_from_data_and_root();
     }
 
     virtual void TearDown() {
@@ -153,12 +149,28 @@
     EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
 }
 
-TEST_F(ServiceTest, RmDexNoDalvikCache) {
-    LOG(INFO) << "RmDexNoDalvikCache";
+TEST_F(ServiceTest, CalculateOat) {
+    char buf[PKG_PATH_MAX];
 
-    // Try to remove a non existing dalvik cache dex. The call should be
-    // successful because there's nothing to remove.
-    EXPECT_TRUE(service->rmdex("com.example", "arm").isOk());
+    EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+
+    EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa"));
+    EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa"));
+}
+
+TEST_F(ServiceTest, CalculateOdex) {
+    char buf[PKG_PATH_MAX];
+
+    EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+}
+
+TEST_F(ServiceTest, CalculateCache) {
+    char buf[PKG_PATH_MAX];
+
+    EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
+    EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 46ed85f..2ca7ac2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <android-base/logging.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
@@ -27,6 +28,7 @@
 #define LOG_TAG "utils_test"
 
 #define TEST_DATA_DIR "/data/"
+#define TEST_ROOT_DIR "/system/"
 #define TEST_APP_DIR "/data/app/"
 #define TEST_APP_PRIVATE_DIR "/data/app-private/"
 #define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
@@ -44,39 +46,13 @@
 class UtilsTest : public testing::Test {
 protected:
     virtual void SetUp() {
-        android_app_dir.path = (char*) TEST_APP_DIR;
-        android_app_dir.len = strlen(TEST_APP_DIR);
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
 
-        android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
-        android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
-
-        android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
-        android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
-
-        android_data_dir.path = (char*) TEST_DATA_DIR;
-        android_data_dir.len = strlen(TEST_DATA_DIR);
-
-        android_asec_dir.path = (char*) TEST_ASEC_DIR;
-        android_asec_dir.len = strlen(TEST_ASEC_DIR);
-
-        android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR;
-        android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR);
-
-        android_system_dirs.count = 2;
-
-        android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
-        android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1;
-        android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
-
-        android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
-        android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
-
-        android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
-        android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
+        init_globals_from_data_and_root(TEST_DATA_DIR, TEST_ROOT_DIR);
     }
 
     virtual void TearDown() {
-        free(android_system_dirs.dirs);
     }
 
     std::string create_too_long_path(const std::string& seed) {
@@ -192,12 +168,6 @@
             << badasec1 << " should be rejected as a invalid path";
 }
 
-TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) {
-    const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk";
-    EXPECT_EQ(-1, validate_apk_path(badasec2))
-            << badasec2 << " should be rejected as a invalid path";
-}
-
 TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) {
     const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk";
     EXPECT_EQ(-1, validate_apk_path(badasec3))
@@ -276,184 +246,6 @@
             << badapp2 << " should be rejected not a system path";
 }
 
-TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
-            << "Should not allow NULL as a path.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, ""))
-            << "Should not allow empty paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_RelativePathFail) {
-    dir_rec_t test1;
-    EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec"))
-            << "Should not allow relative paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_NonCanonical) {
-    dir_rec_t test1;
-
-    EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec"))
-            << "Should be able to canonicalize directory /mnt/asec";
-    EXPECT_STREQ("/mnt/asec/", test1.path)
-            << "/mnt/asec should be canonicalized to /mnt/asec/";
-    EXPECT_EQ(10, (ssize_t) test1.len)
-            << "path len should be equal to the length of /mnt/asec/ (10)";
-    free(test1.path);
-}
-
-TEST_F(UtilsTest, GetPathFromString_CanonicalPath) {
-    dir_rec_t test3;
-    EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/"))
-            << "Should be able to canonicalize directory /data/app/";
-    EXPECT_STREQ("/data/app/", test3.path)
-            << "/data/app/ should be canonicalized to /data/app/";
-    EXPECT_EQ(10, (ssize_t) test3.len)
-            << "path len should be equal to the length of /data/app/ (10)";
-    free(test3.path);
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t pkgnameSize = PKG_NAME_MAX;
-    char pkgname[pkgnameSize + 1];
-    memset(pkgname, 'a', pkgnameSize);
-    pkgname[1] = '.';
-    pkgname[pkgnameSize] = '\0';
-
-    EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
-            << "Should successfully be able to create package name.";
-
-    std::string prefix = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX;
-    size_t offset = prefix.length();
-
-    EXPECT_STREQ(pkgname, path + offset)
-             << "Package path should be a really long string of a's";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
-    char path[PKG_PATH_MAX];
-
-    // Create long packagename of "aaaaa..."
-    size_t postfixSize = PKG_PATH_MAX;
-    char postfix[postfixSize + 1];
-    memset(postfix, 'a', postfixSize);
-    postfix[postfixSize] = '\0';
-
-    EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0))
-            << "Should return error because postfix is too long.";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0))
-            << "Should return error because postfix is too long.";
-
-    std::string p = std::string(TEST_DATA_DIR)
-                    + PRIMARY_USER_PREFIX
-                    + "com.example.package";
-    EXPECT_STREQ(p.c_str(), path)
-            << "Package path should be in /data/data/";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1))
-            << "Should successfully create package path.";
-
-    std::string p = std::string(TEST_DATA_DIR)
-                    + SECONDARY_USER_PREFIX
-                    + "1/com.example.package";
-    EXPECT_STREQ(p.c_str(), path)
-            << "Package path should be in /data/user/";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Primary) {
-    char path[PKG_PATH_MAX];
-
-    EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
-            << "Should be able to create move path for primary user";
-
-    EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
-            << "Primary user package directory should be created correctly";
-}
-
-
-TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
-    char path[PKG_PATH_MAX];
-    std::string really_long_app_name = create_too_long_path("com.example");
-    EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0))
-            << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
-    char path[PKG_PATH_MAX];
-    std::string really_long_leaf_name = create_too_long_path("leaf_");
-    EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0))
-            << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CopyAndAppend_Normal) {
-    //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
-    dir_rec_t dst;
-    dir_rec_t src;
-
-    src.path = (char*) "/data/";
-    src.len = strlen(src.path);
-
-    EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
-            << "Should return error because postfix is too long.";
-
-    EXPECT_STREQ("/data/app/", dst.path)
-            << "Appended path should be correct";
-
-    EXPECT_EQ(10, (ssize_t) dst.len)
-            << "Appended path should be length of '/data/app/' (10)";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_Normal) {
-    size_t dst_size = 10;
-    char dst[dst_size];
-    char *dstp = dst;
-    const char* src = "FOO";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully";
-
-    EXPECT_STREQ("FOO", dst)
-            << "String should append correctly";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully again";
-
-    EXPECT_STREQ("FOOFOO", dst)
-            << "String should append correctly again";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
-    size_t dst_size = 5;
-    char dst[dst_size];
-    char *dstp = dst;
-    const char* src = "FOO";
-
-    EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
-            << "String should append successfully";
-
-    EXPECT_STREQ("FOO", dst)
-            << "String should append correctly";
-
-    EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size))
-            << "String should fail because it's too large to fit";
-}
-
 TEST_F(UtilsTest, CreateDataPath) {
     EXPECT_EQ("/data", create_data_path(nullptr));
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b",
@@ -653,5 +445,29 @@
         package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE);
 }
 
+TEST_F(UtilsTest, ValidateApkPath) {
+    EXPECT_EQ(0, validate_apk_path("/data/app/com.example"));
+    EXPECT_EQ(0, validate_apk_path("/data/app/com.example/file"));
+    EXPECT_EQ(0, validate_apk_path("/data/app/com.example//file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir//file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir/file"));
+    EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir//file"));
+}
+
+TEST_F(UtilsTest, ValidateApkPathSubdirs) {
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example//file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/file"));
+    EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir//file"));
+    EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file"));
+    EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 93d5c0b..ca0a82e 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -129,24 +129,6 @@
             create_data_user_de_path(volume_uuid, user).c_str(), package_name);
 }
 
-int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
-        const char *postfix, userid_t userid) {
-    if (!is_valid_package_name(pkgname)) {
-        path[0] = '\0';
-        return -1;
-    }
-
-    std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
-    const char* tmp = _tmp.c_str();
-    if (strlen(tmp) >= PKG_PATH_MAX) {
-        path[0] = '\0';
-        return -1;
-    } else {
-        strcpy(path, tmp);
-        return 0;
-    }
-}
-
 std::string create_data_path(const char* volume_uuid) {
     if (volume_uuid == nullptr) {
         return "/data";
@@ -213,7 +195,7 @@
 }
 
 std::string create_primary_cur_profile_dir_path(userid_t userid) {
-    return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
+    return StringPrintf("%s/cur/%u", android_profiles_dir.c_str(), userid);
 }
 
 std::string create_primary_current_profile_package_dir_path(userid_t user,
@@ -224,12 +206,12 @@
 }
 
 std::string create_primary_ref_profile_dir_path() {
-    return StringPrintf("%s/ref", android_profiles_dir.path);
+    return StringPrintf("%s/ref", android_profiles_dir.c_str());
 }
 
 std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
     check_package_name(package_name.c_str());
-    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+    return StringPrintf("%s/ref/%s", android_profiles_dir.c_str(), package_name.c_str());
 }
 
 std::string create_data_dalvik_cache_path() {
@@ -378,20 +360,6 @@
     return 0;
 }
 
-int create_move_path(char path[PKG_PATH_MAX],
-    const char* pkgname,
-    const char* leaf,
-    userid_t userid ATTRIBUTE_UNUSED)
-{
-    if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
-            >= PKG_PATH_MAX) {
-        return -1;
-    }
-
-    sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
-    return 0;
-}
-
 /**
  * Checks whether the package name is valid. Returns -1 on error and
  * 0 on success.
@@ -767,22 +735,36 @@
  * The path is allowed to have at most one subdirectory and no indirections
  * to top level directories (i.e. have "..").
  */
-static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
-    size_t dir_len = dir->len;
-    const char* subdir = strchr(path + dir_len, '/');
-
-    // Only allow the path to have at most one subdirectory.
-    if (subdir != NULL) {
-        ++subdir;
-        if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
-            ALOGE("invalid apk path '%s' (subdir?)\n", path);
-            return -1;
-        }
+static int validate_path(const std::string& dir, const std::string& path, int maxSubdirs) {
+    // Argument sanity checking
+    if (dir.find('/') != 0 || dir.rfind('/') != dir.size() - 1
+            || dir.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid directory " << dir;
+        return -1;
+    }
+    if (path.find("..") != std::string::npos) {
+        LOG(ERROR) << "Invalid path " << path;
+        return -1;
     }
 
-    // Directories can't have a period directly after the directory markers to prevent "..".
-    if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
-        ALOGE("invalid apk path '%s' (trickery)\n", path);
+    if (path.compare(0, dir.size(), dir) != 0) {
+        // Common case, path isn't under directory
+        return -1;
+    }
+
+    // Count number of subdirectories
+    auto pos = path.find('/', dir.size());
+    int count = 0;
+    while (pos != std::string::npos) {
+        auto next = path.find('/', pos + 1);
+        if (next > pos + 1) {
+            count++;
+        }
+        pos = next;
+    }
+
+    if (count > maxSubdirs) {
+        LOG(ERROR) << "Invalid path depth " << path << " when tested against " << dir;
         return -1;
     }
 
@@ -794,15 +776,12 @@
  * if it is a system app or -1 if it is not.
  */
 int validate_system_app_path(const char* path) {
-    size_t i;
-
-    for (i = 0; i < android_system_dirs.count; i++) {
-        const size_t dir_len = android_system_dirs.dirs[i].len;
-        if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
-            return validate_path(android_system_dirs.dirs + i, path, 1);
+    std::string path_ = path;
+    for (const auto& dir : android_system_dirs) {
+        if (validate_path(dir, path, 1) == 0) {
+            return 0;
         }
     }
-
     return -1;
 }
 
@@ -840,116 +819,26 @@
 }
 
 /**
- * Get the contents of a environment variable that contains a path. Caller
- * owns the string that is inserted into the directory record. Returns
- * 0 on success and -1 on error.
- */
-int get_path_from_env(dir_rec_t* rec, const char* var) {
-    const char* path = getenv(var);
-    int ret = get_path_from_string(rec, path);
-    if (ret < 0) {
-        ALOGW("Problem finding value for environment variable %s\n", var);
-    }
-    return ret;
-}
-
-/**
- * Puts the string into the record as a directory. Appends '/' to the end
- * of all paths. Caller owns the string that is inserted into the directory
- * record. A null value will result in an error.
- *
- * Returns 0 on success and -1 on error.
- */
-int get_path_from_string(dir_rec_t* rec, const char* path) {
-    if (path == NULL) {
-        return -1;
-    } else {
-        const size_t path_len = strlen(path);
-        if (path_len <= 0) {
-            return -1;
-        }
-
-        // Make sure path is absolute.
-        if (path[0] != '/') {
-            return -1;
-        }
-
-        if (path[path_len - 1] == '/') {
-            // Path ends with a forward slash. Make our own copy.
-
-            rec->path = strdup(path);
-            if (rec->path == NULL) {
-                return -1;
-            }
-
-            rec->len = path_len;
-        } else {
-            // Path does not end with a slash. Generate a new string.
-            char *dst;
-
-            // Add space for slash and terminating null.
-            size_t dst_size = path_len + 2;
-
-            rec->path = (char*) malloc(dst_size);
-            if (rec->path == NULL) {
-                return -1;
-            }
-
-            dst = rec->path;
-
-            if (append_and_increment(&dst, path, &dst_size) < 0
-                    || append_and_increment(&dst, "/", &dst_size)) {
-                ALOGE("Error canonicalizing path");
-                return -1;
-            }
-
-            rec->len = dst - rec->path;
-        }
-    }
-    return 0;
-}
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
-    dst->len = src->len + strlen(suffix);
-    const size_t dstSize = dst->len + 1;
-    dst->path = (char*) malloc(dstSize);
-
-    if (dst->path == NULL
-            || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
-                    != (ssize_t) dst->len) {
-        ALOGE("Could not allocate memory to hold appended path; aborting\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-/**
  * Check whether path points to a valid path for an APK file. The path must
  * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
  * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
  * is encountered.
  */
 static int validate_apk_path_internal(const char *path, int maxSubdirs) {
-    const dir_rec_t* dir = NULL;
-    if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
-        dir = &android_app_dir;
-    } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
-        dir = &android_app_private_dir;
-    } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) {
-        dir = &android_app_ephemeral_dir;
-    } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
-        dir = &android_asec_dir;
-    } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
-        dir = &android_mnt_expand_dir;
-        if (maxSubdirs < 2) {
-            maxSubdirs = 2;
-        }
+    std::string path_ = path;
+    if (validate_path(android_app_dir, path_, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_app_private_dir, path_, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_app_ephemeral_dir, path_, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) {
+        return 0;
+    } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) {
+        return 0;
     } else {
         return -1;
     }
-
-    return validate_path(dir, path, maxSubdirs);
 }
 
 int validate_apk_path(const char* path) {
@@ -960,48 +849,6 @@
     return validate_apk_path_internal(path, 3 /* maxSubdirs */);
 }
 
-int append_and_increment(char** dst, const char* src, size_t* dst_size) {
-    ssize_t ret = strlcpy(*dst, src, *dst_size);
-    if (ret < 0 || (size_t) ret >= *dst_size) {
-        return -1;
-    }
-    *dst += ret;
-    *dst_size -= ret;
-    return 0;
-}
-
-char *build_string2(const char *s1, const char *s2) {
-    if (s1 == NULL || s2 == NULL) return NULL;
-
-    int len_s1 = strlen(s1);
-    int len_s2 = strlen(s2);
-    int len = len_s1 + len_s2 + 1;
-    char *result = (char *) malloc(len);
-    if (result == NULL) return NULL;
-
-    strcpy(result, s1);
-    strcpy(result + len_s1, s2);
-
-    return result;
-}
-
-char *build_string3(const char *s1, const char *s2, const char *s3) {
-    if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
-
-    int len_s1 = strlen(s1);
-    int len_s2 = strlen(s2);
-    int len_s3 = strlen(s3);
-    int len = len_s1 + len_s2 + len_s3 + 1;
-    char *result = (char *) malloc(len);
-    if (result == NULL) return NULL;
-
-    strcpy(result, s1);
-    strcpy(result + len_s1, s2);
-    strcpy(result + len_s1 + len_s2, s3);
-
-    return result;
-}
-
 int ensure_config_user_dirs(userid_t userid) {
     // writable by system, readable by any app within the same user
     const int uid = multiuser_get_uid(userid, AID_SYSTEM);
@@ -1074,7 +921,7 @@
     } else {
         // Mismatched GID/mode is recoverable; fall through to update
         LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
-                << " but expected " << gid;
+                << "/" << actual_mode << " but expected " << gid << "/" << target_mode;
     }
 
     // Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index a1d8443..3e04af9 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -41,18 +41,11 @@
 namespace android {
 namespace installd {
 
-struct dir_rec_t;
-
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
 constexpr const char* kXattrCacheGroup = "user.cache_group";
 constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
-int create_pkg_path(char path[PKG_PATH_MAX],
-                    const char *pkgname,
-                    const char *postfix,
-                    userid_t userid);
-
 std::string create_data_path(const char* volume_uuid);
 
 std::string create_data_app_path(const char* volume_uuid);
@@ -96,11 +89,6 @@
 
 int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
 
-int create_move_path(char path[PKG_PATH_MAX],
-                     const char* pkgname,
-                     const char* leaf,
-                     userid_t userid);
-
 bool is_valid_filename(const std::string& name);
 bool is_valid_package_name(const std::string& packageName);
 
@@ -128,20 +116,9 @@
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
         const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
 
-int get_path_from_env(dir_rec_t* rec, const char* var);
-
-int get_path_from_string(dir_rec_t* rec, const char* path);
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
-
 int validate_apk_path(const char *path);
 int validate_apk_path_subdirs(const char *path);
 
-int append_and_increment(char** dst, const char* src, size_t* dst_size);
-
-char *build_string2(const char *s1, const char *s2);
-char *build_string3(const char *s1, const char *s2, const char *s3);
-
 int ensure_config_user_dirs(userid_t userid);
 
 int wait_child(pid_t pid);
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 31cd0cb..6b340a8 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -138,6 +138,7 @@
     uint32_t handle;
     struct binder_death death;
     int allow_isolated;
+    uint32_t dumpsys_priority;
     size_t len;
     uint16_t name[0];
 };
@@ -198,11 +199,8 @@
     return si->handle;
 }
 
-int do_add_service(struct binder_state *bs,
-                   const uint16_t *s, size_t len,
-                   uint32_t handle, uid_t uid, int allow_isolated,
-                   pid_t spid)
-{
+int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
+                   uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
     struct svcinfo *si;
 
     //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -239,6 +237,7 @@
         si->death.func = (void*) svcinfo_death;
         si->death.ptr = si;
         si->allow_isolated = allow_isolated;
+        si->dumpsys_priority = dumpsys_priority;
         si->next = svclist;
         svclist = si;
     }
@@ -259,6 +258,7 @@
     uint32_t handle;
     uint32_t strict_policy;
     int allow_isolated;
+    uint32_t dumpsys_priority;
 
     //ALOGI("target=%p code=%d pid=%d uid=%d\n",
     //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
@@ -317,13 +317,15 @@
         }
         handle = bio_get_ref(msg);
         allow_isolated = bio_get_uint32(msg) ? 1 : 0;
-        if (do_add_service(bs, s, len, handle, txn->sender_euid,
-            allow_isolated, txn->sender_pid))
+        dumpsys_priority = bio_get_uint32(msg);
+        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
+                           txn->sender_pid))
             return -1;
         break;
 
     case SVC_MGR_LIST_SERVICES: {
         uint32_t n = bio_get_uint32(msg);
+        uint32_t req_dumpsys_priority = bio_get_uint32(msg);
 
         if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
             ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
@@ -331,8 +333,15 @@
             return -1;
         }
         si = svclist;
-        while ((n-- > 0) && si)
+        // walk through the list of services n times skipping services that
+        // do not support the requested priority
+        while (si) {
+            if (si->dumpsys_priority & req_dumpsys_priority) {
+                if (n == 0) break;
+                n--;
+            }
             si = si->next;
+        }
         if (si) {
             bio_put_string16(reply, si->name);
             return 0;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 2b5389b..4140f40 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -24,9 +24,9 @@
 
 #include <gui/BufferQueue.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 #include <ui/DisplayInfo.h>
 #include <utils/Log.h>
@@ -338,27 +338,29 @@
 status_t Replayer::doTransaction(const Transaction& t, const std::shared_ptr<Event>& event) {
     ALOGV("Started Transaction");
 
-    SurfaceComposerClient::openGlobalTransaction();
+    SurfaceComposerClient::Transaction liveTransaction;
 
     status_t status = NO_ERROR;
 
-    status = doSurfaceTransaction(t.surface_change());
-    doDisplayTransaction(t.display_change());
+    status = doSurfaceTransaction(liveTransaction, t.surface_change());
+    doDisplayTransaction(liveTransaction, t.display_change());
 
     if (t.animation()) {
-        SurfaceComposerClient::setAnimationTransaction();
+        liveTransaction.setAnimationTransaction();
     }
 
     event->readyToExecute();
 
-    SurfaceComposerClient::closeGlobalTransaction(t.synchronous());
+    liveTransaction.apply(t.synchronous());
 
     ALOGV("Ended Transaction");
 
     return status;
 }
 
-status_t Replayer::doSurfaceTransaction(const SurfaceChanges& surfaceChanges) {
+status_t Replayer::doSurfaceTransaction(
+        SurfaceComposerClient::Transaction& transaction,
+        const SurfaceChanges& surfaceChanges) {
     status_t status = NO_ERROR;
 
     for (const SurfaceChange& change : surfaceChanges) {
@@ -369,62 +371,66 @@
 
         switch (change.SurfaceChange_case()) {
             case SurfaceChange::SurfaceChangeCase::kPosition:
-                status = setPosition(change.id(), change.position());
+                setPosition(transaction, change.id(), change.position());
                 break;
             case SurfaceChange::SurfaceChangeCase::kSize:
-                status = setSize(change.id(), change.size());
+                setSize(transaction, change.id(), change.size());
                 break;
             case SurfaceChange::SurfaceChangeCase::kAlpha:
-                status = setAlpha(change.id(), change.alpha());
+                setAlpha(transaction, change.id(), change.alpha());
                 break;
             case SurfaceChange::SurfaceChangeCase::kLayer:
-                status = setLayer(change.id(), change.layer());
+                setLayer(transaction, change.id(), change.layer());
                 break;
             case SurfaceChange::SurfaceChangeCase::kCrop:
-                status = setCrop(change.id(), change.crop());
+                setCrop(transaction, change.id(), change.crop());
                 break;
             case SurfaceChange::SurfaceChangeCase::kMatrix:
-                status = setMatrix(change.id(), change.matrix());
+                setMatrix(transaction, change.id(), change.matrix());
                 break;
             case SurfaceChange::SurfaceChangeCase::kFinalCrop:
-                status = setFinalCrop(change.id(), change.final_crop());
+                setFinalCrop(transaction, change.id(), change.final_crop());
                 break;
             case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
-                status = setOverrideScalingMode(change.id(), change.override_scaling_mode());
+                setOverrideScalingMode(transaction, change.id(),
+                        change.override_scaling_mode());
                 break;
             case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
-                status = setTransparentRegionHint(change.id(), change.transparent_region_hint());
+                setTransparentRegionHint(transaction, change.id(),
+                        change.transparent_region_hint());
                 break;
             case SurfaceChange::SurfaceChangeCase::kLayerStack:
-                status = setLayerStack(change.id(), change.layer_stack());
+                setLayerStack(transaction, change.id(), change.layer_stack());
                 break;
             case SurfaceChange::SurfaceChangeCase::kHiddenFlag:
-                status = setHiddenFlag(change.id(), change.hidden_flag());
+                setHiddenFlag(transaction, change.id(), change.hidden_flag());
                 break;
             case SurfaceChange::SurfaceChangeCase::kOpaqueFlag:
-                status = setOpaqueFlag(change.id(), change.opaque_flag());
+                setOpaqueFlag(transaction, change.id(), change.opaque_flag());
                 break;
             case SurfaceChange::SurfaceChangeCase::kSecureFlag:
-                status = setSecureFlag(change.id(), change.secure_flag());
+                setSecureFlag(transaction, change.id(), change.secure_flag());
                 break;
             case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
                 waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock);
-                status = setDeferredTransaction(change.id(), change.deferred_transaction());
+                setDeferredTransaction(transaction, change.id(),
+                        change.deferred_transaction());
                 break;
             default:
-                status = NO_ERROR;
+                status = 1;
                 break;
         }
 
         if (status != NO_ERROR) {
-            ALOGE("SET TRANSACTION FAILED");
+            ALOGE("Unknown Transaction Code");
             return status;
         }
     }
     return status;
 }
 
-void Replayer::doDisplayTransaction(const DisplayChanges& displayChanges) {
+void Replayer::doDisplayTransaction(SurfaceComposerClient::Transaction& t,
+        const DisplayChanges& displayChanges) {
     for (const DisplayChange& change : displayChanges) {
         ALOGV("Doing display transaction");
         std::unique_lock<std::mutex> lock(mDisplayLock);
@@ -434,16 +440,16 @@
 
         switch (change.DisplayChange_case()) {
             case DisplayChange::DisplayChangeCase::kSurface:
-                setDisplaySurface(change.id(), change.surface());
+                setDisplaySurface(t, change.id(), change.surface());
                 break;
             case DisplayChange::DisplayChangeCase::kLayerStack:
-                setDisplayLayerStack(change.id(), change.layer_stack());
+                setDisplayLayerStack(t, change.id(), change.layer_stack());
                 break;
             case DisplayChange::DisplayChangeCase::kSize:
-                setDisplaySize(change.id(), change.size());
+                setDisplaySize(t, change.id(), change.size());
                 break;
             case DisplayChange::DisplayChangeCase::kProjection:
-                setDisplayProjection(change.id(), change.projection());
+                setDisplayProjection(t, change.id(), change.projection());
                 break;
             default:
                 break;
@@ -451,57 +457,66 @@
     }
 }
 
-status_t Replayer::setPosition(layer_id id, const PositionChange& pc) {
+void Replayer::setPosition(SurfaceComposerClient::Transaction& t,
+        layer_id id, const PositionChange& pc) {
     ALOGV("Layer %d: Setting Position -- x=%f, y=%f", id, pc.x(), pc.y());
-    return mLayers[id]->setPosition(pc.x(), pc.y());
+    t.setPosition(mLayers[id], pc.x(), pc.y());
 }
 
-status_t Replayer::setSize(layer_id id, const SizeChange& sc) {
+void Replayer::setSize(SurfaceComposerClient::Transaction& t,
+        layer_id id, const SizeChange& sc) {
     ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h());
-    return mLayers[id]->setSize(sc.w(), sc.h());
+    t.setSize(mLayers[id], sc.w(), sc.h());
 }
 
-status_t Replayer::setLayer(layer_id id, const LayerChange& lc) {
+void Replayer::setLayer(SurfaceComposerClient::Transaction& t,
+        layer_id id, const LayerChange& lc) {
     ALOGV("Layer %d: Setting Layer -- layer=%d", id, lc.layer());
-    return mLayers[id]->setLayer(lc.layer());
+    t.setLayer(mLayers[id], lc.layer());
 }
 
-status_t Replayer::setAlpha(layer_id id, const AlphaChange& ac) {
+void Replayer::setAlpha(SurfaceComposerClient::Transaction& t,
+        layer_id id, const AlphaChange& ac) {
     ALOGV("Layer %d: Setting Alpha -- alpha=%f", id, ac.alpha());
-    return mLayers[id]->setAlpha(ac.alpha());
+    t.setAlpha(mLayers[id], ac.alpha());
 }
 
-status_t Replayer::setCrop(layer_id id, const CropChange& cc) {
+void Replayer::setCrop(SurfaceComposerClient::Transaction& t,
+        layer_id id, const CropChange& cc) {
     ALOGV("Layer %d: Setting Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
             cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
             cc.rectangle().bottom());
 
     Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
             cc.rectangle().bottom());
-    return mLayers[id]->setCrop(r);
+    t.setCrop(mLayers[id], r);
 }
 
-status_t Replayer::setFinalCrop(layer_id id, const FinalCropChange& fcc) {
+void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t,
+        layer_id id, const FinalCropChange& fcc) {
     ALOGV("Layer %d: Setting Final Crop -- left=%d, top=%d, right=%d, bottom=%d", id,
             fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
             fcc.rectangle().bottom());
     Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
             fcc.rectangle().bottom());
-    return mLayers[id]->setFinalCrop(r);
+    t.setFinalCrop(mLayers[id], r);
 }
 
-status_t Replayer::setMatrix(layer_id id, const MatrixChange& mc) {
+void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
+        layer_id id, const MatrixChange& mc) {
     ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(),
             mc.dtdx(), mc.dsdy(), mc.dtdy());
-    return mLayers[id]->setMatrix(mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
+    t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
 }
 
-status_t Replayer::setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc) {
+void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
+        layer_id id, const OverrideScalingModeChange& osmc) {
     ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
-    return mLayers[id]->setOverrideScalingMode(osmc.override_scaling_mode());
+    t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode());
 }
 
-status_t Replayer::setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trhc) {
+void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
+        layer_id id, const TransparentRegionHintChange& trhc) {
     ALOGV("Setting Transparent Region Hint");
     Region re = Region();
 
@@ -510,71 +525,80 @@
         re.merge(rect);
     }
 
-    return mLayers[id]->setTransparentRegionHint(re);
+    t.setTransparentRegionHint(mLayers[id], re);
 }
 
-status_t Replayer::setLayerStack(layer_id id, const LayerStackChange& lsc) {
+void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t,
+        layer_id id, const LayerStackChange& lsc) {
     ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
-    return mLayers[id]->setLayerStack(lsc.layer_stack());
+    t.setLayerStack(mLayers[id], lsc.layer_stack());
 }
 
-status_t Replayer::setHiddenFlag(layer_id id, const HiddenFlagChange& hfc) {
+void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t,
+        layer_id id, const HiddenFlagChange& hfc) {
     ALOGV("Layer %d: Setting Hidden Flag -- hidden_flag=%d", id, hfc.hidden_flag());
     layer_id flag = hfc.hidden_flag() ? layer_state_t::eLayerHidden : 0;
 
-    return mLayers[id]->setFlags(flag, layer_state_t::eLayerHidden);
+    t.setFlags(mLayers[id], flag, layer_state_t::eLayerHidden);
 }
 
-status_t Replayer::setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc) {
+void Replayer::setOpaqueFlag(SurfaceComposerClient::Transaction& t,
+        layer_id id, const OpaqueFlagChange& ofc) {
     ALOGV("Layer %d: Setting Opaque Flag -- opaque_flag=%d", id, ofc.opaque_flag());
     layer_id flag = ofc.opaque_flag() ? layer_state_t::eLayerOpaque : 0;
 
-    return mLayers[id]->setFlags(flag, layer_state_t::eLayerOpaque);
+    t.setFlags(mLayers[id], flag, layer_state_t::eLayerOpaque);
 }
 
-status_t Replayer::setSecureFlag(layer_id id, const SecureFlagChange& sfc) {
+void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t,
+        layer_id id, const SecureFlagChange& sfc) {
     ALOGV("Layer %d: Setting Secure Flag -- secure_flag=%d", id, sfc.secure_flag());
     layer_id flag = sfc.secure_flag() ? layer_state_t::eLayerSecure : 0;
 
-    return mLayers[id]->setFlags(flag, layer_state_t::eLayerSecure);
+    t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure);
 }
 
-status_t Replayer::setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc) {
+void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t,
+        layer_id id, const DeferredTransactionChange& dtc) {
     ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, "
           "frame_number=%llu",
             id, dtc.layer_id(), dtc.frame_number());
     if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) {
         ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id());
-        return BAD_VALUE;
+        return;
     }
 
     auto handle = mLayers[dtc.layer_id()]->getHandle();
 
-    return mLayers[id]->deferTransactionUntil(handle, dtc.frame_number());
+    t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number());
 }
 
-void Replayer::setDisplaySurface(display_id id, const DispSurfaceChange& /*dsc*/) {
+void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
+        display_id id, const DispSurfaceChange& /*dsc*/) {
     sp<IGraphicBufferProducer> outProducer;
     sp<IGraphicBufferConsumer> outConsumer;
     BufferQueue::createBufferQueue(&outProducer, &outConsumer);
 
-    SurfaceComposerClient::setDisplaySurface(mDisplays[id], outProducer);
+    t.setDisplaySurface(mDisplays[id], outProducer);
 }
 
-void Replayer::setDisplayLayerStack(display_id id, const LayerStackChange& lsc) {
-    SurfaceComposerClient::setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
+void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
+        display_id id, const LayerStackChange& lsc) {
+    t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
 }
 
-void Replayer::setDisplaySize(display_id id, const SizeChange& sc) {
-    SurfaceComposerClient::setDisplaySize(mDisplays[id], sc.w(), sc.h());
+void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t,
+        display_id id, const SizeChange& sc) {
+    t.setDisplaySize(mDisplays[id], sc.w(), sc.h());
 }
 
-void Replayer::setDisplayProjection(display_id id, const ProjectionChange& pc) {
+void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t,
+        display_id id, const ProjectionChange& pc) {
     Rect viewport = Rect(pc.viewport().left(), pc.viewport().top(), pc.viewport().right(),
             pc.viewport().bottom());
     Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom());
 
-    SurfaceComposerClient::setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
+    t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
 }
 
 status_t Replayer::createSurfaceControl(
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index f36c9fd..295403e 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -77,28 +77,48 @@
     void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event);
     void updatePowerMode(const PowerModeUpdate& update, const std::shared_ptr<Event>& event);
 
-    status_t doSurfaceTransaction(const SurfaceChanges& surfaceChange);
-    void doDisplayTransaction(const DisplayChanges& displayChange);
+    status_t doSurfaceTransaction(SurfaceComposerClient::Transaction& transaction,
+            const SurfaceChanges& surfaceChange);
+    void doDisplayTransaction(SurfaceComposerClient::Transaction& transaction,
+            const DisplayChanges& displayChange);
 
-    status_t setPosition(layer_id id, const PositionChange& pc);
-    status_t setSize(layer_id id, const SizeChange& sc);
-    status_t setAlpha(layer_id id, const AlphaChange& ac);
-    status_t setLayer(layer_id id, const LayerChange& lc);
-    status_t setCrop(layer_id id, const CropChange& cc);
-    status_t setFinalCrop(layer_id id, const FinalCropChange& fcc);
-    status_t setMatrix(layer_id id, const MatrixChange& mc);
-    status_t setOverrideScalingMode(layer_id id, const OverrideScalingModeChange& osmc);
-    status_t setTransparentRegionHint(layer_id id, const TransparentRegionHintChange& trgc);
-    status_t setLayerStack(layer_id id, const LayerStackChange& lsc);
-    status_t setHiddenFlag(layer_id id, const HiddenFlagChange& hfc);
-    status_t setOpaqueFlag(layer_id id, const OpaqueFlagChange& ofc);
-    status_t setSecureFlag(layer_id id, const SecureFlagChange& sfc);
-    status_t setDeferredTransaction(layer_id id, const DeferredTransactionChange& dtc);
+    void setPosition(SurfaceComposerClient::Transaction& t,
+            layer_id id, const PositionChange& pc);
+    void setSize(SurfaceComposerClient::Transaction& t,
+            layer_id id, const SizeChange& sc);
+    void setAlpha(SurfaceComposerClient::Transaction& t,
+            layer_id id, const AlphaChange& ac);
+    void setLayer(SurfaceComposerClient::Transaction& t,
+            layer_id id, const LayerChange& lc);
+    void setCrop(SurfaceComposerClient::Transaction& t,
+            layer_id id, const CropChange& cc);
+    void setFinalCrop(SurfaceComposerClient::Transaction& t,
+            layer_id id, const FinalCropChange& fcc);
+    void setMatrix(SurfaceComposerClient::Transaction& t,
+            layer_id id, const MatrixChange& mc);
+    void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
+            layer_id id, const OverrideScalingModeChange& osmc);
+    void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
+            layer_id id, const TransparentRegionHintChange& trgc);
+    void setLayerStack(SurfaceComposerClient::Transaction& t,
+            layer_id id, const LayerStackChange& lsc);
+    void setHiddenFlag(SurfaceComposerClient::Transaction& t,
+            layer_id id, const HiddenFlagChange& hfc);
+    void setOpaqueFlag(SurfaceComposerClient::Transaction& t,
+            layer_id id, const OpaqueFlagChange& ofc);
+    void setSecureFlag(SurfaceComposerClient::Transaction& t,
+            layer_id id, const SecureFlagChange& sfc);
+    void setDeferredTransaction(SurfaceComposerClient::Transaction& t,
+            layer_id id, const DeferredTransactionChange& dtc);
 
-    void setDisplaySurface(display_id id, const DispSurfaceChange& dsc);
-    void setDisplayLayerStack(display_id id, const LayerStackChange& lsc);
-    void setDisplaySize(display_id id, const SizeChange& sc);
-    void setDisplayProjection(display_id id, const ProjectionChange& pc);
+    void setDisplaySurface(SurfaceComposerClient::Transaction& t,
+            display_id id, const DispSurfaceChange& dsc);
+    void setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
+            display_id id, const LayerStackChange& lsc);
+    void setDisplaySize(SurfaceComposerClient::Transaction& t,
+            display_id id, const SizeChange& sc);
+    void setDisplayProjection(SurfaceComposerClient::Transaction& t,
+            display_id id, const ProjectionChange& pc);
 
     void doDeleteSurfaceControls();
     void waitUntilTimestamp(int64_t timestamp);
diff --git a/data/etc/android.hardware.wifi.rtt.xml b/data/etc/android.hardware.wifi.rtt.xml
new file mode 100644
index 0000000..60529ea
--- /dev/null
+++ b/data/etc/android.hardware.wifi.rtt.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device supports WiFi RTT (IEEE 802.11mc). -->
+<permissions>
+    <feature name="android.hardware.wifi.rtt" />
+</permissions>
diff --git a/include/android/sensor.h b/include/android/sensor.h
index a88733c..2db0ee7 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -197,7 +197,7 @@
  * A sensor event.
  */
 
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to these structs have to be backward compatible */
 typedef struct ASensorVector {
     union {
         float v[3];
@@ -259,7 +259,7 @@
     };
 } AAdditionalInfoEvent;
 
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to this struct has to be backward compatible */
 typedef struct ASensorEvent {
     int32_t version; /* sizeof(struct ASensorEvent) */
     int32_t sensor;
diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h
deleted file mode 100644
index de5c1c7..0000000
--- a/include/audiomanager/IPlayer.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IPLAYER_H
-#define ANDROID_IPLAYER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <media/VolumeShaper.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IPlayer : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(Player);
-
-    virtual void start() = 0;
-
-    virtual void pause() = 0;
-
-    virtual void stop() = 0;
-
-    virtual void setVolume(float vol) = 0;
-
-    virtual void setPan(float pan) = 0;
-
-    virtual void setStartDelayMs(int delayMs) = 0;
-
-    virtual void applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnPlayer : public BnInterface<IPlayer>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPLAYER_H
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 795f575..ffa1614 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -264,6 +264,40 @@
     Movement mMovements[HISTORY_SIZE];
 };
 
+class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy {
+public:
+    ImpulseVelocityTrackerStrategy();
+    virtual ~ImpulseVelocityTrackerStrategy();
+
+    virtual void clear();
+    virtual void clearPointers(BitSet32 idBits);
+    virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
+            const VelocityTracker::Position* positions);
+    virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+
+private:
+    // Sample horizon.
+    // We don't use too much history by default since we want to react to quick
+    // changes in direction.
+    static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms
+
+    // Number of samples to keep.
+    static constexpr size_t HISTORY_SIZE = 20;
+
+    struct Movement {
+        nsecs_t eventTime;
+        BitSet32 idBits;
+        VelocityTracker::Position positions[MAX_POINTERS];
+
+        inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+            return positions[idBits.getIndexOfBit(id)];
+        }
+    };
+
+    size_t mIndex;
+    Movement mMovements[HISTORY_SIZE];
+};
+
 } // namespace android
 
 #endif // _LIBINPUT_VELOCITY_TRACKER_H
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c7a0f43..70f5108 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -161,19 +161,18 @@
     }
 
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
-            bool allowIsolated)
-    {
+                                bool allowIsolated, int dumpsysPriority) {
         Parcel data, reply;
         data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
         data.writeString16(name);
         data.writeStrongBinder(service);
         data.writeInt32(allowIsolated ? 1 : 0);
+        data.writeInt32(dumpsysPriority);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
         return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
 
-    virtual Vector<String16> listServices()
-    {
+    virtual Vector<String16> listServices(int dumpsysPriority) {
         Vector<String16> res;
         int n = 0;
 
@@ -181,6 +180,7 @@
             Parcel data, reply;
             data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
             data.writeInt32(n++);
+            data.writeInt32(dumpsysPriority);
             status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
             if (err != NO_ERROR)
                 break;
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index ef703bd..4e69067 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -34,15 +34,16 @@
 class BinderService
 {
 public:
-    static status_t publish(bool allowIsolated = false) {
+    static status_t publish(bool allowIsolated = false,
+                            int dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL) {
         sp<IServiceManager> sm(defaultServiceManager());
-        return sm->addService(
-                String16(SERVICE::getServiceName()),
-                new SERVICE(), allowIsolated);
+        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
+                              dumpPriority);
     }
 
-    static void publishAndJoinThreadPool(bool allowIsolated = false) {
-        publish(allowIsolated);
+    static void publishAndJoinThreadPool(bool allowIsolated = false,
+                                         int dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL) {
+        publish(allowIsolated, dumpPriority);
         joinThreadPool();
     }
 
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3b23f81..78b03bd 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -31,6 +31,14 @@
 {
 public:
     DECLARE_META_INTERFACE(ServiceManager)
+    /*
+     * 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;
 
     /**
      * Retrieve an existing service, blocking for a few seconds
@@ -46,14 +54,14 @@
     /**
      * Register a service.
      */
-    virtual status_t            addService( const String16& name,
-                                            const sp<IBinder>& service,
-                                            bool allowIsolated = false) = 0;
+    virtual status_t addService(const String16& name, const sp<IBinder>& service,
+                                bool allowIsolated = false,
+                                int dumpsysPriority = DUMP_PRIORITY_NORMAL) = 0;
 
     /**
      * Return list of all existing services.
      */
-    virtual Vector<String16>    listServices() = 0;
+    virtual Vector<String16> listServices(int dumpsysPriority = DUMP_PRIORITY_ALL) = 0;
 
     enum {
         GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 455f2c4..bf41e0b 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -215,7 +215,7 @@
         int target = cs_pair ? num % server_count : rand() % workers.size();
         int sz = payload_size;
 
-        while (sz > sizeof(uint32_t)) {
+        while (sz >= sizeof(uint32_t)) {
             data.writeInt32(0);
             sz -= sizeof(uint32_t);
         }
@@ -381,6 +381,7 @@
             // No need to run training round in this case.
             if (atoi(argv[i+1]) > 0) {
                 max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000;
+                time_per_bucket = max_time_bucket / num_buckets;
                 i++;
             } else {
                 cout << "Max latency -m must be positive." << endl;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8e7f814..9677125 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -29,8 +29,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerDebugInfo.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
 
 #include <system/graphics.h>
 
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index 57ddde0..d3dc16d 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -43,7 +43,10 @@
     RETURN_ON_ERROR(parcel->writeInt32(mHeight));
     RETURN_ON_ERROR(parcel->write(mCrop));
     RETURN_ON_ERROR(parcel->write(mFinalCrop));
-    RETURN_ON_ERROR(parcel->writeFloat(mAlpha));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.a));
     RETURN_ON_ERROR(parcel->writeUint32(mFlags));
     RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat));
     RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace)));
@@ -79,7 +82,14 @@
     RETURN_ON_ERROR(parcel->readInt32(&mHeight));
     RETURN_ON_ERROR(parcel->read(mCrop));
     RETURN_ON_ERROR(parcel->read(mFinalCrop));
-    RETURN_ON_ERROR(parcel->readFloat(&mAlpha));
+    mColor.r = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.g = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.b = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.a = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
     RETURN_ON_ERROR(parcel->readUint32(&mFlags));
     RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat));
     // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways?
@@ -116,8 +126,10 @@
     result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
     result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
     result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
-    result.appendFormat("alpha=%.3f, flags=0x%08x, ",
-            static_cast<double>(info.mAlpha), info.mFlags);
+    result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+            static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
+            static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
+            info.mFlags);
     result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
             static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
             static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 9b06e63..bfc6f28 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -18,7 +18,7 @@
 #include <binder/Parcel.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/IGraphicBufferProducer.h>
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
 
 namespace android {
 
@@ -45,6 +45,10 @@
     output.writeInt32(overrideScalingMode);
     output.writeStrongBinder(IInterface::asBinder(barrierGbp));
     output.writeStrongBinder(relativeLayerHandle);
+    output.writeStrongBinder(parentHandleForChild);
+    output.writeFloat(color.r);
+    output.writeFloat(color.g);
+    output.writeFloat(color.b);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -77,6 +81,10 @@
     barrierGbp =
         interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     relativeLayerHandle = input.readStrongBinder();
+    parentHandleForChild = input.readStrongBinder();
+    color.r = input.readFloat();
+    color.g = input.readFloat();
+    color.b = input.readFloat();
     input.read(transparentRegion);
     return NO_ERROR;
 }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d9d945d..e939383 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1512,6 +1512,12 @@
     return NO_ERROR;
 }
 
+android_dataspace_t Surface::getBuffersDataSpace() {
+    ALOGV("Surface::getBuffersDataSpace");
+    Mutex::Autolock lock(mMutex);
+    return mDataSpace;
+}
+
 void Surface::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i].buffer = 0;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7ae2672..40e319e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -21,7 +21,6 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include <utils/Singleton.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
@@ -37,11 +36,11 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -97,204 +96,71 @@
 
 // ---------------------------------------------------------------------------
 
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
-    if (lhs.client < rhs.client)  return -1;
-    if (lhs.client > rhs.client)  return 1;
-    if (lhs.state.surface < rhs.state.surface)  return -1;
-    if (lhs.state.surface > rhs.state.surface)  return 1;
-    return 0;
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
+    mForceSynchronous(other.mForceSynchronous),
+    mTransactionNestCount(other.mTransactionNestCount),
+    mAnimation(other.mAnimation) {
+    mDisplayStates = other.mDisplayStates;
+    mComposerStates = other.mComposerStates;
 }
 
-static inline
-int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
-    return compare_type(lhs.token, rhs.token);
+status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
+    if (mStatus != NO_ERROR) {
+        return mStatus;
+    }
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+    Vector<ComposerState> composerStates;
+    Vector<DisplayState> displayStates;
+    uint32_t flags = 0;
+
+    mForceSynchronous |= synchronous;
+
+    composerStates = mComposerStates;
+    mComposerStates.clear();
+
+    displayStates = mDisplayStates;
+    mDisplayStates.clear();
+
+    if (mForceSynchronous) {
+        flags |= ISurfaceComposer::eSynchronous;
+    }
+    if (mAnimation) {
+        flags |= ISurfaceComposer::eAnimation;
+    }
+
+    mForceSynchronous = false;
+    mAnimation = false;
+
+    sf->setTransactionState(composerStates, displayStates, flags);
+    mStatus = NO_ERROR;
+    return NO_ERROR;
 }
 
-class Composer : public Singleton<Composer>
-{
-    friend class Singleton<Composer>;
-
-    mutable Mutex               mLock;
-    SortedVector<ComposerState> mComposerStates;
-    SortedVector<DisplayState > mDisplayStates;
-    uint32_t                    mForceSynchronous;
-    uint32_t                    mTransactionNestCount;
-    bool                        mAnimation;
-
-    Composer() : Singleton<Composer>(),
-        mForceSynchronous(0), mTransactionNestCount(0),
-        mAnimation(false)
-    { }
-
-    void openGlobalTransactionImpl();
-    void closeGlobalTransactionImpl(bool synchronous);
-    void setAnimationTransactionImpl();
-    status_t enableVSyncInjectionsImpl(bool enable);
-    status_t injectVSyncImpl(nsecs_t when);
-
-    layer_state_t* getLayerStateLocked(
-            const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
-
-    DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
-
-public:
-    sp<IBinder> createDisplay(const String8& displayName, bool secure);
-    void destroyDisplay(const sp<IBinder>& display);
-    sp<IBinder> getBuiltInDisplay(int32_t id);
-
-    status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float x, float y);
-    status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t w, uint32_t h);
-    status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            int32_t z);
-    status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const sp<IBinder>& relativeTo, int32_t z);
-    status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            uint32_t flags, uint32_t mask);
-    status_t setTransparentRegionHint(
-            const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const Region& transparentRegion);
-    status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float alpha);
-    status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t setOrientation(int orientation);
-    status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
-            const Rect& crop);
-    status_t setFinalCrop(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const Rect& crop);
-    status_t setLayerStack(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, uint32_t layerStack);
-    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const sp<IBinder>& handle,
-            uint64_t frameNumber);
-    status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, const sp<Surface>& barrierSurface,
-            uint64_t frameNumber);
-    status_t reparentChildren(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id,
-            const sp<IBinder>& newParentHandle);
-    status_t detachChildren(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id);
-    status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id, int32_t overrideScalingMode);
-    status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client,
-            const sp<IBinder>& id);
-
-    status_t setDisplaySurface(const sp<IBinder>& token,
-            sp<IGraphicBufferProducer> bufferProducer);
-    void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
-    void setDisplayProjection(const sp<IBinder>& token,
-            uint32_t orientation,
-            const Rect& layerStackRect,
-            const Rect& displayRect);
-    void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
-    static void setAnimationTransaction() {
-        Composer::getInstance().setAnimationTransactionImpl();
-    }
-
-    static void openGlobalTransaction() {
-        Composer::getInstance().openGlobalTransactionImpl();
-    }
-
-    static void closeGlobalTransaction(bool synchronous) {
-        Composer::getInstance().closeGlobalTransactionImpl(synchronous);
-    }
-
-    static status_t enableVSyncInjections(bool enable) {
-        return Composer::getInstance().enableVSyncInjectionsImpl(enable);
-    }
-
-    static status_t injectVSync(nsecs_t when) {
-        return Composer::getInstance().injectVSyncImpl(when);
-    }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
-
 // ---------------------------------------------------------------------------
 
-sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) {
+sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
     return ComposerService::getComposerService()->createDisplay(displayName,
             secure);
 }
 
-void Composer::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->destroyDisplay(display);
 }
 
-sp<IBinder> Composer::getBuiltInDisplay(int32_t id) {
+sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
     return ComposerService::getComposerService()->getBuiltInDisplay(id);
 }
 
-void Composer::openGlobalTransactionImpl() {
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        mTransactionNestCount += 1;
-    }
-}
-
-void Composer::closeGlobalTransactionImpl(bool synchronous) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-
-    Vector<ComposerState> transaction;
-    Vector<DisplayState> displayTransaction;
-    uint32_t flags = 0;
-
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        mForceSynchronous |= synchronous;
-        if (!mTransactionNestCount) {
-            ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior "
-                    "call to openGlobalTransaction().");
-        } else if (--mTransactionNestCount) {
-            return;
-        }
-
-        transaction = mComposerStates;
-        mComposerStates.clear();
-
-        displayTransaction = mDisplayStates;
-        mDisplayStates.clear();
-
-        if (mForceSynchronous) {
-            flags |= ISurfaceComposer::eSynchronous;
-        }
-        if (mAnimation) {
-            flags |= ISurfaceComposer::eAnimation;
-        }
-
-        mForceSynchronous = false;
-        mAnimation = false;
-    }
-
-   sm->setTransactionState(transaction, displayTransaction, flags);
-}
-
-status_t Composer::enableVSyncInjectionsImpl(bool enable) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return sm->enableVSyncInjections(enable);
-}
-
-status_t Composer::injectVSyncImpl(nsecs_t when) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return sm->injectVSync(when);
-}
-
-void Composer::setAnimationTransactionImpl() {
-    Mutex::Autolock _l(mLock);
+void SurfaceComposerClient::Transaction::setAnimationTransaction() {
     mAnimation = true;
 }
 
-layer_state_t* Composer::getLayerStateLocked(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) {
-
+layer_state_t* SurfaceComposerClient::Transaction::getLayerStateLocked(const sp<SurfaceControl>& sc) {
     ComposerState s;
-    s.client = client->mClient;
-    s.state.surface = id;
+    s.client = sc->getClient()->mClient;
+    s.state.surface = sc->getHandle();
 
     ssize_t index = mComposerStates.indexOf(s);
     if (index < 0) {
@@ -306,24 +172,36 @@
     return &(out[index].state);
 }
 
-status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float x, float y) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
+        const sp<SurfaceControl>& sc, float x, float y) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::ePositionChanged;
     s->x = x;
     s->y = y;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show(
+        const sp<SurfaceControl>& sc) {
+    return setFlags(sc, 0, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide(
+        const sp<SurfaceControl>& sc) {
+    return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize(
+        const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eSizeChanged;
     s->w = w;
     s->h = h;
@@ -331,41 +209,41 @@
     // Resizing a surface makes the transaction synchronous.
     mForceSynchronous = true;
 
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, int32_t z) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer(
+        const sp<SurfaceControl>& sc, int32_t z) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eLayerChanged;
     s->z = z;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const sp<IBinder>& relativeTo,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo,
         int32_t z) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eRelativeLayerChanged;
     s->relativeLayerHandle = relativeTo;
     s->z = z;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t flags,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags(
+        const sp<SurfaceControl>& sc, uint32_t flags,
         uint32_t mask) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     if ((mask & layer_state_t::eLayerOpaque) ||
             (mask & layer_state_t::eLayerHidden) ||
             (mask & layer_state_t::eLayerSecure)) {
@@ -374,50 +252,54 @@
     s->flags &= ~mask;
     s->flags |= (flags & mask);
     s->mask |= mask;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setTransparentRegionHint(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint(
+        const sp<SurfaceControl>& sc,
         const Region& transparentRegion) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eTransparentRegionChanged;
     s->transparentRegion = transparentRegion;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float alpha) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha(
+        const sp<SurfaceControl>& sc, float alpha) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eAlphaChanged;
     s->alpha = alpha;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, uint32_t layerStack) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack(
+        const sp<SurfaceControl>& sc, uint32_t layerStack) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eLayerStackChanged;
     s->layerStack = layerStack;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, float dsdx, float dtdx,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix(
+        const sp<SurfaceControl>& sc, float dsdx, float dtdx,
         float dtdy, float dsdy) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eMatrixChanged;
     layer_state_t::matrix22_t matrix;
     matrix.dsdx = dsdx;
@@ -425,93 +307,115 @@
     matrix.dsdy = dsdy;
     matrix.dtdy = dtdy;
     s->matrix = matrix;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const Rect& crop) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
-    if (!s)
-        return BAD_INDEX;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+        const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
     s->what |= layer_state_t::eCropChanged;
     s->crop = crop;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, const Rect& crop) {
-    Mutex::Autolock _l(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eFinalCropChanged;
     s->finalCrop = crop;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::deferTransactionUntil(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+        const sp<SurfaceControl>& sc,
         const sp<IBinder>& handle, uint64_t frameNumber) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eDeferTransaction;
     s->barrierHandle = handle;
     s->frameNumber = frameNumber;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::deferTransactionUntil(
-        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
+        const sp<SurfaceControl>& sc,
         const sp<Surface>& barrierSurface, uint64_t frameNumber) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eDeferTransaction;
     s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
     s->frameNumber = frameNumber;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::reparentChildren(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id,
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren(
+        const sp<SurfaceControl>& sc,
         const sp<IBinder>& newParentHandle) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eReparentChildren;
     s->reparentHandle = newParentHandle;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::detachChildren(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent(
+        const sp<SurfaceControl>& sc,
+        const sp<IBinder>& newParentHandle) {
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eReparent;
+    s->parentHandleForChild = newParentHandle;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor(
+        const sp<SurfaceControl>& sc,
+        const half3& color) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorChanged;
+    s->color = color;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerStateLocked(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eDetachChildren;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setOverrideScalingMode(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id, int32_t overrideScalingMode) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode(
+        const sp<SurfaceControl>& sc, int32_t overrideScalingMode) {
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
 
     switch (overrideScalingMode) {
@@ -524,29 +428,29 @@
         default:
             ALOGE("unknown scaling mode: %d",
                     overrideScalingMode);
-            return BAD_VALUE;
+            mStatus = BAD_VALUE;
+            return *this;
     }
 
     s->what |= layer_state_t::eOverrideScalingModeChanged;
     s->overrideScalingMode = overrideScalingMode;
-    return NO_ERROR;
+    return *this;
 }
 
-status_t Composer::setGeometryAppliesWithResize(
-        const sp<SurfaceComposerClient>& client,
-        const sp<IBinder>& id) {
-    Mutex::Autolock lock(mLock);
-    layer_state_t* s = getLayerStateLocked(client, id);
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize(
+        const sp<SurfaceControl>& sc) {
+    layer_state_t* s = getLayerStateLocked(sc);
     if (!s) {
-        return BAD_INDEX;
+        mStatus = BAD_INDEX;
+        return *this;
     }
     s->what |= layer_state_t::eGeometryAppliesWithResize;
-    return NO_ERROR;
+    return *this;
 }
 
 // ---------------------------------------------------------------------------
 
-DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
+DisplayState& SurfaceComposerClient::Transaction::getDisplayStateLocked(const sp<IBinder>& token) {
     DisplayState s;
     s.token = token;
     ssize_t index = mDisplayStates.indexOf(s);
@@ -558,8 +462,8 @@
     return mDisplayStates.editItemAt(static_cast<size_t>(index));
 }
 
-status_t Composer::setDisplaySurface(const sp<IBinder>& token,
-        sp<IGraphicBufferProducer> bufferProducer) {
+status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
+        const sp<IGraphicBufferProducer>& bufferProducer) {
     if (bufferProducer.get() != nullptr) {
         // Make sure that composition can never be stalled by a virtual display
         // consumer that isn't processing buffers fast enough.
@@ -571,26 +475,23 @@
             return err;
         }
     }
-    Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.surface = bufferProducer;
     s.what |= DisplayState::eSurfaceChanged;
     return NO_ERROR;
 }
 
-void Composer::setDisplayLayerStack(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token,
         uint32_t layerStack) {
-    Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.layerStack = layerStack;
     s.what |= DisplayState::eLayerStackChanged;
 }
 
-void Composer::setDisplayProjection(const sp<IBinder>& token,
+void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
         uint32_t orientation,
         const Rect& layerStackRect,
         const Rect& displayRect) {
-    Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.orientation = orientation;
     s.viewport = layerStackRect;
@@ -599,8 +500,7 @@
     mForceSynchronous = true; // TODO: do we actually still need this?
 }
 
-void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
-    Mutex::Autolock _l(mLock);
+void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) {
     DisplayState& s(getDisplayStateLocked(token));
     s.width = width;
     s.height = height;
@@ -610,22 +510,22 @@
 // ---------------------------------------------------------------------------
 
 SurfaceComposerClient::SurfaceComposerClient()
-    : mStatus(NO_INIT), mComposer(Composer::getInstance())
+    : mStatus(NO_INIT)
 {
 }
 
 SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
-    : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root)
+    : mStatus(NO_INIT), mParent(root)
 {
 }
 
 void SurfaceComposerClient::onFirstRef() {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    if (sm != 0) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    if (sf != 0) {
         auto rootProducer = mParent.promote();
         sp<ISurfaceComposerClient> conn;
-        conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
-                sm->createConnection();
+        conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
+                sf->createConnection();
         if (conn != 0) {
             mClient = conn;
             mStatus = NO_ERROR;
@@ -648,8 +548,8 @@
 status_t SurfaceComposerClient::linkToComposerDeath(
         const sp<IBinder::DeathRecipient>& recipient,
         void* cookie, uint32_t flags) {
-    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
-    return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags);
 }
 
 void SurfaceComposerClient::dispose() {
@@ -692,19 +592,6 @@
     return sur;
 }
 
-sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
-        bool secure) {
-    return Composer::getInstance().createDisplay(displayName, secure);
-}
-
-void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) {
-    Composer::getInstance().destroyDisplay(display);
-}
-
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
-    return Composer::getInstance().getBuiltInDisplay(id);
-}
-
 status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
     if (mStatus != NO_ERROR)
         return mStatus;
@@ -727,152 +614,18 @@
     return mClient->getLayerFrameStats(token, outStats);
 }
 
-inline Composer& SurfaceComposerClient::getComposer() {
-    return mComposer;
-}
-
 // ----------------------------------------------------------------------------
 
-void SurfaceComposerClient::openGlobalTransaction() {
-    Composer::openGlobalTransaction();
-}
-
-void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
-    Composer::closeGlobalTransaction(synchronous);
-}
-
-void SurfaceComposerClient::setAnimationTransaction() {
-    Composer::setAnimationTransaction();
-}
-
 status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
-    return Composer::enableVSyncInjections(enable);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return sf->enableVSyncInjections(enable);
 }
 
 status_t SurfaceComposerClient::injectVSync(nsecs_t when) {
-    return Composer::injectVSync(when);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    return sf->injectVSync(when);
 }
 
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
-    return getComposer().setCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id,
-        const Rect& crop) {
-    return getComposer().setFinalCrop(this, id, crop);
-}
-
-status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) {
-    return getComposer().setPosition(this, id, x, y);
-}
-
-status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) {
-    return getComposer().setSize(this, id, w, h);
-}
-
-status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) {
-    return getComposer().setLayer(this, id, z);
-}
-
-status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id,
-        const sp<IBinder>& relativeTo, int32_t z) {
-    return getComposer().setRelativeLayer(this, id, relativeTo, z);
-}
-
-status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
-    return getComposer().setFlags(this, id,
-            layer_state_t::eLayerHidden,
-            layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(const sp<IBinder>& id) {
-    return getComposer().setFlags(this, id,
-            0,
-            layer_state_t::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags,
-        uint32_t mask) {
-    return getComposer().setFlags(this, id, flags, mask);
-}
-
-status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id,
-        const Region& transparentRegion) {
-    return getComposer().setTransparentRegionHint(this, id, transparentRegion);
-}
-
-status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) {
-    return getComposer().setAlpha(this, id, alpha);
-}
-
-status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) {
-    return getComposer().setLayerStack(this, id, layerStack);
-}
-
-status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx,
-        float dtdy, float dsdy) {
-    return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
-        const sp<IBinder>& handle, uint64_t frameNumber) {
-    return getComposer().deferTransactionUntil(this, id, handle, frameNumber);
-}
-
-status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id,
-        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
-    return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber);
-}
-
-status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id,
-        const sp<IBinder>& newParentHandle) {
-    return getComposer().reparentChildren(this, id, newParentHandle);
-}
-
-status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
-    return getComposer().detachChildren(this, id);
-}
-
-status_t SurfaceComposerClient::setOverrideScalingMode(
-        const sp<IBinder>& id, int32_t overrideScalingMode) {
-    return getComposer().setOverrideScalingMode(
-            this, id, overrideScalingMode);
-}
-
-status_t SurfaceComposerClient::setGeometryAppliesWithResize(
-        const sp<IBinder>& id) {
-    return getComposer().setGeometryAppliesWithResize(this, id);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
-        sp<IGraphicBufferProducer> bufferProducer) {
-    return Composer::getInstance().setDisplaySurface(token, bufferProducer);
-}
-
-void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
-        uint32_t layerStack) {
-    Composer::getInstance().setDisplayLayerStack(token, layerStack);
-}
-
-void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token,
-        uint32_t orientation,
-        const Rect& layerStackRect,
-        const Rect& displayRect) {
-    Composer::getInstance().setDisplayProjection(token, orientation,
-            layerStackRect, displayRect);
-}
-
-void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token,
-        uint32_t width, uint32_t height) {
-    Composer::getInstance().setDisplaySize(token, width, height);
-}
-
-// ----------------------------------------------------------------------------
-
 status_t SurfaceComposerClient::getDisplayConfigs(
         const sp<IBinder>& display, Vector<DisplayInfo>* configs)
 {
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 58bd273..f6a2b8f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -97,112 +97,6 @@
     return lhs->mHandle == rhs->mHandle;
 }
 
-status_t SurfaceControl::setLayerStack(uint32_t layerStack) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setLayerStack(mHandle, layerStack);
-}
-
-status_t SurfaceControl::setLayer(int32_t layer) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setLayer(mHandle, layer);
-}
-
-status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setRelativeLayer(mHandle, relativeTo, layer);
-}
-
-status_t SurfaceControl::setPosition(float x, float y) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setPosition(mHandle, x, y);
-}
-status_t SurfaceControl::setGeometryAppliesWithResize() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setGeometryAppliesWithResize(mHandle);
-}
-status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setSize(mHandle, w, h);
-}
-status_t SurfaceControl::hide() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->hide(mHandle);
-}
-status_t SurfaceControl::show() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->show(mHandle);
-}
-status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setFlags(mHandle, flags, mask);
-}
-status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setTransparentRegionHint(mHandle, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setAlpha(mHandle, alpha);
-}
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy);
-}
-status_t SurfaceControl::setCrop(const Rect& crop) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setCrop(mHandle, crop);
-}
-status_t SurfaceControl::setFinalCrop(const Rect& crop) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setFinalCrop(mHandle, crop);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle,
-        uint64_t frameNumber) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle,
-        uint64_t frameNumber) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->deferTransactionUntil(mHandle, handle, frameNumber);
-}
-
-status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->reparentChildren(mHandle, newParentHandle);
-}
-
-status_t SurfaceControl::detachChildren() {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->detachChildren(mHandle);
-}
-
-status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) {
-    status_t err = validate();
-    if (err < 0) return err;
-    return mClient->setOverrideScalingMode(mHandle, overrideScalingMode);
-}
-
 status_t SurfaceControl::clearLayerFrameStats() const {
     status_t err = validate();
     if (err < 0) return err;
@@ -267,5 +161,10 @@
     return mHandle;
 }
 
+sp<SurfaceComposerClient> SurfaceControl::getClient() const
+{
+    return mClient;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2c613ea..d5bbef2 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -41,7 +41,7 @@
         eCursorWindow = 0x00002000,
 
         eFXSurfaceNormal = 0x00000000,
-        eFXSurfaceDim = 0x00020000,
+        eFXSurfaceColor = 0x00020000,
         eFXSurfaceMask = 0x000F0000,
     };
 
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 8453e04..92bd8c5 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -22,6 +22,7 @@
 #include <ui/Region.h>
 
 #include <string>
+#include <math/vec4.h>
 
 namespace android {
 
@@ -52,7 +53,7 @@
     int32_t mHeight = -1;
     Rect mCrop = Rect::INVALID_RECT;
     Rect mFinalCrop = Rect::INVALID_RECT;
-    float mAlpha = 0.f;
+    half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
     uint32_t mFlags = 0;
     PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
     android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
similarity index 86%
rename from libs/gui/include/private/gui/LayerState.h
rename to libs/gui/include/gui/LayerState.h
index 307c764..ae6965a 100644
--- a/libs/gui/include/private/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -25,6 +25,7 @@
 #include <ui/Region.h>
 #include <ui/Rect.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -59,7 +60,9 @@
         eGeometryAppliesWithResize  = 0x00001000,
         eReparentChildren           = 0x00002000,
         eDetachChildren             = 0x00004000,
-        eRelativeLayerChanged       = 0x00008000
+        eRelativeLayerChanged       = 0x00008000,
+        eReparent                   = 0x00010000,
+        eColorChanged               = 0x00020000
     };
 
     layer_state_t()
@@ -107,6 +110,10 @@
 
             sp<IBinder>     relativeLayerHandle;
 
+            sp<IBinder>     parentHandleForChild;
+
+            half3           color;
+
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
@@ -150,6 +157,20 @@
     status_t read(const Parcel& input);
 };
 
+static inline
+int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+    if (lhs.client < rhs.client) return -1;
+    if (lhs.client > rhs.client) return 1;
+    if (lhs.state.surface < rhs.state.surface)  return -1;
+    if (lhs.state.surface > rhs.state.surface)  return 1;
+    return 0;
+}
+
+static inline
+int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+    return compare_type(lhs.token, rhs.token);
+}
+
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55dd6bf..3fe29d9 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -281,6 +281,8 @@
     // detachNextBuffer, or attachBuffer call.
     status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
 
+    android_dataspace_t getBuffersDataSpace();
+
 protected:
     enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 145c059..00d5936 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -32,13 +32,14 @@
 
 #include <gui/CpuConsumer.h>
 #include <gui/SurfaceControl.h>
+#include <math/vec3.h>
+#include <gui/LayerState.h>
 
 namespace android {
 
 // ---------------------------------------------------------------------------
 
 struct DisplayInfo;
-class Composer;
 class HdrCapabilities;
 class ISurfaceComposerClient;
 class IGraphicBufferProducer;
@@ -121,91 +122,158 @@
     //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
     static sp<IBinder> getBuiltInDisplay(int32_t id);
 
-    // ------------------------------------------------------------------------
-    // Composer parameters
-    // All composer parameters must be changed within a transaction
-    // several surfaces can be updated in one transaction, all changes are
-    // committed at once when the transaction is closed.
-    // closeGlobalTransaction() requires an IPC with the server.
-
-    //! Open a composer transaction on all active SurfaceComposerClients.
-    static void openGlobalTransaction();
-
-    //! Close a composer transaction on all active SurfaceComposerClients.
-    static void closeGlobalTransaction(bool synchronous = false);
-
     static status_t enableVSyncInjections(bool enable);
 
     static status_t injectVSync(nsecs_t when);
 
-    //! Flag the currently open transaction as an animation transaction.
-    static void setAnimationTransaction();
+    class Transaction {
+        SortedVector<ComposerState> mComposerStates;
+        SortedVector<DisplayState > mDisplayStates;
+        uint32_t                    mForceSynchronous = 0;
+        uint32_t                    mTransactionNestCount = 0;
+        bool                        mAnimation = false;
 
-    status_t    hide(const sp<IBinder>& id);
-    status_t    show(const sp<IBinder>& id);
-    status_t    setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
-    status_t    setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
-    status_t    setLayer(const sp<IBinder>& id, int32_t layer);
-    status_t    setRelativeLayer(const sp<IBinder>& id,
-            const sp<IBinder>& relativeTo, int32_t layer);
-    status_t    setAlpha(const sp<IBinder>& id, float alpha=1.0f);
-    status_t    setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t    setPosition(const sp<IBinder>& id, float x, float y);
-    status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
-    status_t    setCrop(const sp<IBinder>& id, const Rect& crop);
-    status_t    setFinalCrop(const sp<IBinder>& id, const Rect& crop);
-    status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
-    status_t    deferTransactionUntil(const sp<IBinder>& id,
-            const sp<IBinder>& handle, uint64_t frameNumber);
-    status_t    deferTransactionUntil(const sp<IBinder>& id,
-            const sp<Surface>& handle, uint64_t frameNumber);
-    status_t    reparentChildren(const sp<IBinder>& id,
-            const sp<IBinder>& newParentHandle);
-    status_t    detachChildren(const sp<IBinder>& id);
-    status_t    setOverrideScalingMode(const sp<IBinder>& id,
-            int32_t overrideScalingMode);
-    status_t    setGeometryAppliesWithResize(const sp<IBinder>& id);
+        int mStatus = NO_ERROR;
+
+        layer_state_t* getLayerStateLocked(const sp<SurfaceControl>& sc);
+        DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
+
+    public:
+        Transaction() = default;
+        virtual ~Transaction() = default;
+        Transaction(Transaction const& other);
+
+        status_t apply(bool synchronous = false);
+
+        Transaction& show(const sp<SurfaceControl>& sc);
+        Transaction& hide(const sp<SurfaceControl>& sc);
+        Transaction& setPosition(const sp<SurfaceControl>& sc,
+                float x, float y);
+        Transaction& setSize(const sp<SurfaceControl>& sc,
+                uint32_t w, uint32_t h);
+        Transaction& setLayer(const sp<SurfaceControl>& sc,
+                int32_t z);
+
+        // Sets a Z order relative to the Surface specified by "relativeTo" but
+        // without becoming a full child of the relative. Z-ordering works exactly
+        // as if it were a child however.
+        //
+        // As a nod to sanity, only non-child surfaces may have a relative Z-order.
+        //
+        // This overrides any previous call and is overriden by any future calls
+        // to setLayer.
+        //
+        // If the relative is removed, the Surface will have no layer and be
+        // invisible, until the next time set(Relative)Layer is called.
+        Transaction& setRelativeLayer(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& relativeTo, int32_t z);
+        Transaction& setFlags(const sp<SurfaceControl>& sc,
+                uint32_t flags, uint32_t mask);
+        Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
+                const Region& transparentRegion);
+        Transaction& setAlpha(const sp<SurfaceControl>& sc,
+                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);
+        // Defers applying any changes made in this transaction until the Layer
+        // identified by handle reaches the given frameNumber. If the Layer identified
+        // by handle is removed, then we will apply this transaction regardless of
+        // what frame number has been reached.
+        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& handle,
+                uint64_t frameNumber);
+        // A variant of deferTransactionUntil which identifies the Layer we wait for by
+        // Surface instead of Handle. Useful for clients which may not have the
+        // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
+        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
+                const sp<Surface>& barrierSurface,
+                uint64_t frameNumber);
+        // Reparents all children of this layer to the new parent handle.
+        Transaction& reparentChildren(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& newParentHandle);
+
+        /// Reparents the current layer to the new parent handle. The new parent must not be null.
+        // This can be used instead of reparentChildren if the caller wants to
+        // only re-parent a specific child.
+        Transaction& reparent(const sp<SurfaceControl>& sc,
+                const sp<IBinder>& newParentHandle);
+
+        Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
+
+        // Detaches all child surfaces (and their children recursively)
+        // from their SurfaceControl.
+        // The child SurfaceControls will not throw exceptions or return errors,
+        // but transactions will have no effect.
+        // The child surfaces will continue to follow their parent surfaces,
+        // and remain eligible for rendering, but their relative state will be
+        // frozen. We use this in the WindowManager, in app shutdown/relaunch
+        // scenarios, where the app would otherwise clean up its child Surfaces.
+        // Sometimes the WindowManager needs to extend their lifetime slightly
+        // in order to perform an exit animation or prevent flicker.
+        Transaction& detachChildren(const sp<SurfaceControl>& sc);
+        // Set an override scaling mode as documented in <system/window.h>
+        // the override scaling mode will take precedence over any client
+        // specified scaling mode. -1 will clear the override scaling mode.
+        Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
+                int32_t overrideScalingMode);
+
+        // If the size changes in this transaction, all geometry updates specified
+        // in this transaction will not complete until a buffer of the new size
+        // arrives. As some elements normally apply immediately, this enables
+        // freezing the total geometry of a surface until a resize is completed.
+        Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
+
+        status_t setDisplaySurface(const sp<IBinder>& token,
+                const sp<IGraphicBufferProducer>& bufferProducer);
+
+        void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+
+        /* setDisplayProjection() defines the projection of layer stacks
+         * to a given display.
+         *
+         * - orientation defines the display's orientation.
+         * - layerStackRect defines which area of the window manager coordinate
+         * space will be used.
+         * - displayRect defines where on the display will layerStackRect be
+         * mapped to. displayRect is specified post-orientation, that is
+         * it uses the orientation seen by the end-user.
+         */
+        void setDisplayProjection(const sp<IBinder>& token,
+                uint32_t orientation,
+                const Rect& layerStackRect,
+                const Rect& displayRect);
+        void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
+        void setAnimationTransaction();
+    };
 
     status_t    destroySurface(const sp<IBinder>& id);
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
     status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
-
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
     static status_t getHdrCapabilities(const sp<IBinder>& display,
             HdrCapabilities* outCapabilities);
 
-    static status_t setDisplaySurface(const sp<IBinder>& token,
-            sp<IGraphicBufferProducer> bufferProducer);
-    static void setDisplayLayerStack(const sp<IBinder>& token,
-            uint32_t layerStack);
-    static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
-
-    /* setDisplayProjection() defines the projection of layer stacks
-     * to a given display.
-     *
-     * - orientation defines the display's orientation.
-     * - layerStackRect defines which area of the window manager coordinate
-     * space will be used.
-     * - displayRect defines where on the display will layerStackRect be
-     * mapped to. displayRect is specified post-orientation, that is
-     * it uses the orientation seen by the end-user.
-     */
     static void setDisplayProjection(const sp<IBinder>& token,
             uint32_t orientation,
             const Rect& layerStackRect,
             const Rect& displayRect);
 
+    inline sp<ISurfaceComposerClient> getClient() { return mClient; }
+
 private:
     virtual void onFirstRef();
-    Composer& getComposer();
 
     mutable     Mutex                       mLock;
                 status_t                    mStatus;
                 sp<ISurfaceComposerClient>  mClient;
-                Composer&                   mComposer;
                 wp<IGraphicBufferProducer>  mParent;
 };
 
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index c15209d..384815d 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -29,6 +29,7 @@
 #include <ui/Region.h>
 
 #include <gui/ISurfaceComposerClient.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -60,87 +61,6 @@
     // disconnect any api that's connected
     void        disconnect();
 
-    status_t    setLayerStack(uint32_t layerStack);
-    status_t    setLayer(int32_t layer);
-
-    // Sets a Z order relative to the Surface specified by "relativeTo" but
-    // without becoming a full child of the relative. Z-ordering works exactly
-    // as if it were a child however.
-    //
-    // As a nod to sanity, only non-child surfaces may have a relative Z-order.
-    //
-    // This overrides any previous and is overriden by any future calls
-    // to setLayer.
-    //
-    // If the relative dissapears, the Surface will have no layer and be
-    // invisible, until the next time set(Relative)Layer is called.
-    //
-    // TODO: This is probably a hack. Currently it exists only to work around
-    // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type
-    // which allows inserting a window between a SurfaceView and it's main application
-    // window. However, since we are using child windows for the SurfaceView, but not using
-    // child windows elsewhere in O, the WindowManager can't set the layer appropriately.
-    // This is only used by the "TvInputService" and following the port of ViewRootImpl
-    // to child surfaces, we can then port this and remove this method.
-    status_t    setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer);
-    status_t    setPosition(float x, float y);
-    status_t    setSize(uint32_t w, uint32_t h);
-    status_t    hide();
-    status_t    show();
-    status_t    setFlags(uint32_t flags, uint32_t mask);
-    status_t    setTransparentRegionHint(const Region& transparent);
-    status_t    setAlpha(float alpha=1.0f);
-
-    // Experimentarily it appears that the matrix transforms the
-    // on-screen rectangle and it's contents before the position is
-    // applied.
-    //
-    // TODO: Test with other combinations to find approximate transformation rules.
-    //
-    // For example:
-    // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives
-    // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y))
-    status_t    setMatrix(float dsdx, float dtdx, float dtdy, float dsdy);
-    status_t    setCrop(const Rect& crop);
-    status_t    setFinalCrop(const Rect& crop);
-
-    // If the size changes in this transaction, all geometry updates specified
-    // in this transaction will not complete until a buffer of the new size
-    // arrives. As some elements normally apply immediately, this enables
-    // freezing the total geometry of a surface until a resize is completed.
-    status_t    setGeometryAppliesWithResize();
-
-    // Defers applying any changes made in this transaction until the Layer
-    // identified by handle reaches the given frameNumber. If the Layer identified
-    // by handle is removed, then we will apply this transaction regardless of
-    // what frame number has been reached.
-    status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
-
-    // A variant of deferTransactionUntil which identifies the Layer we wait for by
-    // Surface instead of Handle. Useful for clients which may not have the
-    // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
-    status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber);
-
-    // Reparents all children of this layer to the new parent handle.
-    status_t reparentChildren(const sp<IBinder>& newParentHandle);
-
-    // Detaches all child surfaces (and their children recursively)
-    // from their SurfaceControl.
-    // The child SurfaceControl's will not throw exceptions or return errors,
-    // but transactions will have no effect.
-    // The child surfaces will continue to follow their parent surfaces,
-    // and remain eligible for rendering, but their relative state will be
-    // frozen. We use this in the WindowManager, in app shutdown/relaunch
-    // scenarios, where the app would otherwise clean up its child Surfaces.
-    // Sometimes the WindowManager needs to extend their lifetime slightly
-    // in order to perform an exit animation or prevent flicker.
-    status_t detachChildren();
-
-    // Set an override scaling mode as documented in <system/window.h>
-    // the override scaling mode will take precedence over any client
-    // specified scaling mode. -1 will clear the override scaling mode.
-    status_t setOverrideScalingMode(int32_t overrideScalingMode);
-
     static status_t writeSurfaceToParcel(
             const sp<SurfaceControl>& control, Parcel* parcel);
 
@@ -151,6 +71,8 @@
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
+    sp<SurfaceComposerClient> getClient() const;
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index 1739d9c..a91552f 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -22,6 +22,8 @@
 
 namespace android {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 static int abs(int value) {
     return value > 0 ? value : -value;
 }
@@ -68,10 +70,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        Transaction t;
+        ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF)
+                .show(mSurfaceControl)
+                .apply());
 
         sp<ANativeWindow> window = mSurfaceControl->getSurface();
         mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ca43c68..572760e 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -42,6 +42,8 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 static bool hasWideColorDisplay =
         getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
@@ -69,10 +71,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        SurfaceComposerClient::openGlobalTransaction();
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff));
-        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction();
+        Transaction t;
+        ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff)
+                .show(mSurfaceControl)
+                .apply());
 
         mSurface = mSurfaceControl->getSurface();
         ASSERT_TRUE(mSurface != NULL);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 9abd04c..b8901bd 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -254,7 +254,7 @@
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
-            "downTime=%lld, eventTime=%lld",
+            "downTime=%" PRId64 ", eventTime=%" PRId64,
             mChannel->getName().string(), seq,
             deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             downTime, eventTime);
@@ -305,7 +305,7 @@
     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
             "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
-            "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
+            "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
             "pointerCount=%" PRIu32,
             mChannel->getName().string(), seq,
             deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
@@ -401,7 +401,7 @@
         bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
         int32_t* displayId) {
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
+    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
             mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
 #endif
 
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 62acea3..e54f147 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -75,7 +75,9 @@
     str += " ]";
     return str;
 }
+#endif
 
+#if DEBUG_STRATEGY
 static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
     std::string str;
     str = "[";
@@ -141,6 +143,11 @@
 }
 
 VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
+    if (!strcmp("impulse", strategy)) {
+        // Physical model of pushing an object.  Quality: VERY GOOD.
+        // Works with duplicate coordinates, unclean finger liftoff.
+        return new ImpulseVelocityTrackerStrategy();
+    }
     if (!strcmp("lsq1", strategy)) {
         // 1st order least squares.  Quality: POOR.
         // Frequently underfits the touch data especially when the finger accelerates
@@ -352,9 +359,6 @@
 
 // --- LeastSquaresVelocityTrackerStrategy ---
 
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
 LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
         uint32_t degree, Weighting weighting) :
         mDegree(degree), mWeighting(weighting) {
@@ -863,10 +867,6 @@
 
 // --- LegacyVelocityTrackerStrategy ---
 
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
 LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
     clear();
 }
@@ -979,4 +979,194 @@
     return true;
 }
 
+// --- ImpulseVelocityTrackerStrategy ---
+
+ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() {
+    clear();
+}
+
+ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
+}
+
+void ImpulseVelocityTrackerStrategy::clear() {
+    mIndex = 0;
+    mMovements[0].idBits.clear();
+}
+
+void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
+    BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+    mMovements[mIndex].idBits = remainingIdBits;
+}
+
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+        const VelocityTracker::Position* positions) {
+    if (++mIndex == HISTORY_SIZE) {
+        mIndex = 0;
+    }
+
+    Movement& movement = mMovements[mIndex];
+    movement.eventTime = eventTime;
+    movement.idBits = idBits;
+    uint32_t count = idBits.count();
+    for (uint32_t i = 0; i < count; i++) {
+        movement.positions[i] = positions[i];
+    }
+}
+
+/**
+ * Calculate the total impulse provided to the screen and the resulting velocity.
+ *
+ * The touchscreen is modeled as a physical object.
+ * Initial condition is discussed below, but for now suppose that v(t=0) = 0
+ *
+ * The kinetic energy of the object at the release is E=0.5*m*v^2
+ * Then vfinal = sqrt(2E/m). The goal is to calculate E.
+ *
+ * The kinetic energy at the release is equal to the total work done on the object by the finger.
+ * The total work W is the sum of all dW along the path.
+ *
+ * dW = F*dx, where dx is the piece of path traveled.
+ * Force is change of momentum over time, F = dp/dt = m dv/dt.
+ * Then substituting:
+ * dW = m (dv/dt) * dx = m * v * dv
+ *
+ * Summing along the path, we get:
+ * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv)
+ * Since the mass stays constant, the equation for final velocity is:
+ * vfinal = sqrt(2*sum(v * dv))
+ *
+ * Here,
+ * dv : change of velocity = (v[i+1]-v[i])
+ * dx : change of distance = (x[i+1]-x[i])
+ * dt : change of time = (t[i+1]-t[i])
+ * v : instantaneous velocity = dx/dt
+ *
+ * The final formula is:
+ * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i
+ * The absolute value is needed to properly account for the sign. If the velocity over a
+ * particular segment descreases, then this indicates braking, which means that negative
+ * work was done. So for two positive, but decreasing, velocities, this contribution would be
+ * negative and will cause a smaller final velocity.
+ *
+ * Initial condition
+ * There are two ways to deal with initial condition:
+ * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest.
+ * This is not entirely accurate. We are only taking the past X ms of touch data, where X is
+ * currently equal to 100. However, a touch event that created a fling probably lasted for longer
+ * than that, which would mean that the user has already been interacting with the touchscreen
+ * and it has probably already been moving.
+ * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this
+ * initial velocity and the equivalent energy, and start with this initial energy.
+ * Consider an example where we have the following data, consisting of 3 points:
+ *                 time: t0, t1, t2
+ *                 x   : x0, x1, x2
+ *                 v   : 0 , v1, v2
+ * Here is what will happen in each of these scenarios:
+ * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get
+ * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0
+ * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1)))
+ * since velocity is a real number
+ * 2) If we treat the screen as already moving, then it must already have an energy (per mass)
+ * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment
+ * will contribute to the total kinetic energy (since we can effectively consider that v0=v1).
+ * This will give the following expression for the final velocity:
+ * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1)))
+ * This analysis can be generalized to an arbitrary number of samples.
+ *
+ *
+ * Comparing the two equations above, we see that the only mathematical difference
+ * is the factor of 1/2 in front of the first velocity term.
+ * This boundary condition would allow for the "proper" calculation of the case when all of the
+ * samples are equally spaced in time and distance, which should suggest a constant velocity.
+ *
+ * Note that approach 2) is sensitive to the proper ordering of the data in time, since
+ * the boundary condition must be applied to the oldest sample to be accurate.
+ */
+static float kineticEnergyToVelocity(float work) {
+    static constexpr float sqrt2 = 1.41421356237;
+    return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+}
+
+static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
+    // The input should be in reversed time order (most recent sample at index i=0)
+    // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
+    static constexpr float NANOS_PER_SECOND = 1E-9;
+
+    if (count < 2) {
+        return 0; // if 0 or 1 points, velocity is zero
+    }
+    if (t[1] > t[0]) { // Algorithm will still work, but not perfectly
+        ALOGE("Samples provided to calculateImpulseVelocity in the wrong order");
+    }
+    if (count == 2) { // if 2 points, basic linear calculation
+        if (t[1] == t[0]) {
+            ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]);
+            return 0;
+        }
+        return (x[1] - x[0]) / (NANOS_PER_SECOND * (t[1] - t[0]));
+    }
+    // Guaranteed to have at least 3 points here
+    float work = 0;
+    for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time
+        if (t[i] == t[i-1]) {
+            ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]);
+            continue;
+        }
+        float vprev = kineticEnergyToVelocity(work); // v[i-1]
+        float vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1])); // v[i]
+        work += (vcurr - vprev) * fabsf(vcurr);
+        if (i == count - 1) {
+            work *= 0.5; // initial condition, case 2) above
+        }
+    }
+    return kineticEnergyToVelocity(work);
+}
+
+bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
+        VelocityTracker::Estimator* outEstimator) const {
+    outEstimator->clear();
+
+    // Iterate over movement samples in reverse time order and collect samples.
+    float x[HISTORY_SIZE];
+    float y[HISTORY_SIZE];
+    nsecs_t time[HISTORY_SIZE];
+    size_t m = 0; // number of points that will be used for fitting
+    size_t index = mIndex;
+    const Movement& newestMovement = mMovements[mIndex];
+    do {
+        const Movement& movement = mMovements[index];
+        if (!movement.idBits.hasBit(id)) {
+            break;
+        }
+
+        nsecs_t age = newestMovement.eventTime - movement.eventTime;
+        if (age > HORIZON) {
+            break;
+        }
+
+        const VelocityTracker::Position& position = movement.getPosition(id);
+        x[m] = position.x;
+        y[m] = position.y;
+        time[m] = movement.eventTime;
+        index = (index == 0 ? HISTORY_SIZE : index) - 1;
+    } while (++m < HISTORY_SIZE);
+
+    if (m == 0) {
+        return false; // no data
+    }
+    outEstimator->xCoeff[0] = 0;
+    outEstimator->yCoeff[0] = 0;
+    outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
+    outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
+    outEstimator->xCoeff[2] = 0;
+    outEstimator->yCoeff[2] = 0;
+    outEstimator->time = newestMovement.eventTime;
+    outEstimator->degree = 2; // similar results to 2nd degree fit
+    outEstimator->confidence = 1;
+#if DEBUG_STRATEGY
+    ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+#endif
+    return true;
+}
+
 } // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 0028655..e0bab11 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -6,6 +6,7 @@
         "InputChannel_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "VelocityTracker_test.cpp",
     ],
     cflags: [
         "-Wall",
@@ -19,6 +20,7 @@
         "libutils",
         "libbinder",
         "libui",
+        "libbase",
     ]
 }
 
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
new file mode 100644
index 0000000..43b6012
--- /dev/null
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VelocityTracker_test"
+
+#include <math.h>
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <input/VelocityTracker.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests
+
+// velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV
+// here EV = expected value, tol = VELOCITY_TOLERANCE
+constexpr float VELOCITY_TOLERANCE = 0.2;
+
+// --- VelocityTrackerTest ---
+class VelocityTrackerTest : public testing::Test { };
+
+static void checkVelocity(float Vactual, float Vtarget) {
+    // Compare directions
+    if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) {
+        FAIL() << StringPrintf("Velocity %f does not have the same direction"
+                " as the target velocity %f", Vactual, Vtarget);
+    }
+
+    // Compare magnitudes
+    const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE));
+    const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE));
+    if (fabsf(Vactual) < Vlower) {
+        FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f",
+                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    }
+    if (fabsf(Vactual) > Vupper) {
+        FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f",
+                Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+    }
+    SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)",
+            Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+}
+
+void failWithMessage(std::string message) {
+    FAIL() << message; // cannot do this directly from a non-void function
+}
+
+struct Position {
+      nsecs_t time;
+      float x;
+      float y;
+};
+
+
+MotionEvent* createSimpleMotionEvent(const Position* positions, size_t numSamples) {
+    /**
+     * Only populate the basic fields of a MotionEvent, such as time and a single axis
+     * Designed for use with manually-defined tests.
+     * Create a new MotionEvent on the heap, caller responsible for destroying the object.
+     */
+    if (numSamples < 1) {
+        failWithMessage(StringPrintf("Need at least 1 sample to create a MotionEvent."
+                " Received numSamples=%zu", numSamples));
+    }
+
+    MotionEvent* event = new MotionEvent();
+    PointerCoords coords;
+    PointerProperties properties[1];
+
+    properties[0].id = DEFAULT_POINTER_ID;
+    properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+    // First sample added separately with initialize
+    coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
+    coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
+    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+
+    for (size_t i = 1; i < numSamples; i++) {
+        coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
+        coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[i].y);
+        event->addSample(positions[i].time, &coords);
+    }
+    return event;
+}
+
+static void computeAndCheckVelocity(const Position* positions, size_t numSamples,
+            int32_t axis, float targetVelocity) {
+    VelocityTracker vt(nullptr);
+    float Vx, Vy;
+
+    MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+    vt.addMovement(event);
+
+    vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
+
+    switch (axis) {
+    case AMOTION_EVENT_AXIS_X:
+        checkVelocity(Vx, targetVelocity);
+        break;
+    case AMOTION_EVENT_AXIS_Y:
+        checkVelocity(Vy, targetVelocity);
+        break;
+    default:
+        FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
+    }
+    delete event;
+}
+
+/*
+ * ================== VelocityTracker tests generated manually =====================================
+ */
+ // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) {
+    // Same coordinate is reported 2 times in a row
+    // It is difficult to determine the correct answer here, but at least the direction
+    // of the reported velocity should be positive.
+    Position values[] = {
+        { 0, 273, NAN },
+        { 12585000, 293, NAN },
+        { 14730000, 293, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) {
+    // Same coordinate is reported 3 times in a row
+    Position values[] = {
+        { 0, 293, NAN },
+        { 6132000, 293, NAN },
+        { 11283000, 293, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0);
+}
+
+TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) {
+    // Fixed velocity at 5 points per 10 milliseconds
+    Position values[] = {
+        { 0, 0, NAN },
+        { 10000000, 5, NAN },
+        { 20000000, 10, NAN },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500);
+}
+
+
+/**
+ * ================== VelocityTracker tests generated by recording real events =====================
+ *
+ * To add a test, record the input coordinates and event times to all calls
+ * to void VelocityTracker::addMovement(const MotionEvent* event).
+ * Also record all calls to VelocityTracker::clear().
+ * Finally, record the output of VelocityTracker::getVelocity(...)
+ * This will give you the necessary data to create a new test.
+ */
+
+// --------------- Recorded by hand on swordfish ---------------------------------------------------
+// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
+TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) {
+    // Recording of a fling on Swordfish that could cause a fling in the wrong direction
+    Position values[] = {
+        { 0, 271, 96 },
+        { 16071042, 269.786346, 106.922775 },
+        { 35648403, 267.983063, 156.660034 },
+        { 52313925, 262.638397, 220.339081 },
+        { 68976522, 266.138824, 331.581116 },
+        { 85639375, 274.79245, 428.113159 },
+        { 96948871, 274.79245, 428.113159 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 623.577637);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 8523.348633);
+}
+
+// --------------- Recorded by hand on sailfish, generated by a script -----------------------------
+// For some of these tests, the X-direction velocity checking has been removed, because the lsq2
+// and the impulse VelocityTrackerStrategies did not agree within 20%.
+// Since the flings were recorded in the Y-direction, the intentional user action should only
+// be relevant for the Y axis.
+// There have been also cases where lsq2 and impulse disagreed more than 20% in the Y-direction.
+// Those recordings have been discarded because we didn't feel one strategy's interpretation was
+// more correct than another's but didn't want to increase the tolerance for the entire test suite.
+//
+// There are 18 tests total below: 9 in the positive Y direction and 9 in the opposite.
+// The recordings were loosely binned into 3 categories - slow, faster, and fast, which roughly
+// characterizes the velocity of the finger motion.
+// These can be treated approximately as:
+// slow - less than 1 page gets scrolled
+// faster - more than 1 page gets scrolled, but less than 3
+// fast - entire list is scrolled (fling is done as hard as possible)
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow1) {
+    // Sailfish - fling up - slow - 1
+    Position values[] = {
+        { 235089067457000, 528.00, 983.00 },
+        { 235089084684000, 527.00, 981.00 },
+        { 235089093349000, 527.00, 977.00 },
+        { 235089095677625, 527.00, 975.93 },
+        { 235089101859000, 527.00, 970.00 },
+        { 235089110378000, 528.00, 960.00 },
+        { 235089112497111, 528.25, 957.51 },
+        { 235089118760000, 531.00, 946.00 },
+        { 235089126686000, 535.00, 931.00 },
+        { 235089129316820, 536.33, 926.02 },
+        { 235089135199000, 540.00, 914.00 },
+        { 235089144297000, 546.00, 896.00 },
+        { 235089146136443, 547.21, 892.36 },
+        { 235089152923000, 553.00, 877.00 },
+        { 235089160784000, 559.00, 851.00 },
+        { 235089162955851, 560.66, 843.82 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 872.794617); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 951.698181); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3604.819336); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3044.966064); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow2) {
+    // Sailfish - fling up - slow - 2
+    Position values[] = {
+        { 235110560704000, 522.00, 1107.00 },
+        { 235110575764000, 522.00, 1107.00 },
+        { 235110584385000, 522.00, 1107.00 },
+        { 235110588421179, 521.52, 1106.52 },
+        { 235110592830000, 521.00, 1106.00 },
+        { 235110601385000, 520.00, 1104.00 },
+        { 235110605088160, 519.14, 1102.27 },
+        { 235110609952000, 518.00, 1100.00 },
+        { 235110618353000, 517.00, 1093.00 },
+        { 235110621755146, 516.60, 1090.17 },
+        { 235110627010000, 517.00, 1081.00 },
+        { 235110634785000, 518.00, 1063.00 },
+        { 235110638422450, 518.87, 1052.58 },
+        { 235110643161000, 520.00, 1039.00 },
+        { 235110651767000, 524.00, 1011.00 },
+        { 235110655089581, 525.54, 1000.19 },
+        { 235110660368000, 530.00, 980.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4096.583008); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3455.094238); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpSlow3) {
+    // Sailfish - fling up - slow - 3
+    Position values[] = {
+        { 792536237000, 580.00, 1317.00 },
+        { 792541538987, 580.63, 1311.94 },
+        { 792544613000, 581.00, 1309.00 },
+        { 792552301000, 583.00, 1295.00 },
+        { 792558362309, 585.13, 1282.92 },
+        { 792560828000, 586.00, 1278.00 },
+        { 792569446000, 589.00, 1256.00 },
+        { 792575185095, 591.54, 1241.41 },
+        { 792578491000, 593.00, 1233.00 },
+        { 792587044000, 597.00, 1211.00 },
+        { 792592008172, 600.28, 1195.92 },
+        { 792594616000, 602.00, 1188.00 },
+        { 792603129000, 607.00, 1167.00 },
+        { 792608831290, 609.48, 1155.83 },
+        { 792612321000, 611.00, 1149.00 },
+        { 792620768000, 615.00, 1131.00 },
+        { 792625653873, 617.32, 1121.73 },
+        { 792629200000, 619.00, 1115.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 574.33429); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 617.40564); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2361.982666); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -2500.055664); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster1) {
+    // Sailfish - fling up - faster - 1
+    Position values[] = {
+        { 235160420675000, 610.00, 1042.00 },
+        { 235160428220000, 609.00, 1026.00 },
+        { 235160436544000, 609.00, 1024.00 },
+        { 235160441852394, 609.64, 1020.82 },
+        { 235160444878000, 610.00, 1019.00 },
+        { 235160452673000, 613.00, 1006.00 },
+        { 235160458519743, 617.18, 992.06 },
+        { 235160461061000, 619.00, 986.00 },
+        { 235160469798000, 627.00, 960.00 },
+        { 235160475186713, 632.22, 943.02 },
+        { 235160478051000, 635.00, 934.00 },
+        { 235160486489000, 644.00, 906.00 },
+        { 235160491853697, 649.56, 890.56 },
+        { 235160495177000, 653.00, 881.00 },
+        { 235160504148000, 662.00, 858.00 },
+        { 235160509231495, 666.81, 845.37 },
+        { 235160512603000, 670.00, 837.00 },
+        { 235160520366000, 679.00, 814.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1274.141724); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1438.53186); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3877.35498); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -3695.859619); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster2) {
+    // Sailfish - fling up - faster - 2
+    Position values[] = {
+        { 847153808000, 576.00, 1264.00 },
+        { 847171174000, 576.00, 1262.00 },
+        { 847179640000, 576.00, 1257.00 },
+        { 847185187540, 577.41, 1249.22 },
+        { 847187487000, 578.00, 1246.00 },
+        { 847195710000, 581.00, 1227.00 },
+        { 847202027059, 583.93, 1209.40 },
+        { 847204324000, 585.00, 1203.00 },
+        { 847212672000, 590.00, 1176.00 },
+        { 847218861395, 594.36, 1157.11 },
+        { 847221190000, 596.00, 1150.00 },
+        { 847230484000, 602.00, 1124.00 },
+        { 847235701400, 607.56, 1103.83 },
+        { 847237986000, 610.00, 1095.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4280.07959); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -4241.004395); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFaster3) {
+    // Sailfish - fling up - faster - 3
+    Position values[] = {
+        { 235200532789000, 507.00, 1084.00 },
+        { 235200549221000, 507.00, 1083.00 },
+        { 235200557841000, 507.00, 1081.00 },
+        { 235200558051189, 507.00, 1080.95 },
+        { 235200566314000, 507.00, 1078.00 },
+        { 235200574876586, 508.97, 1070.12 },
+        { 235200575006000, 509.00, 1070.00 },
+        { 235200582900000, 514.00, 1054.00 },
+        { 235200591276000, 525.00, 1023.00 },
+        { 235200591701829, 525.56, 1021.42 },
+        { 235200600064000, 542.00, 976.00 },
+        { 235200608519000, 563.00, 911.00 },
+        { 235200608527086, 563.02, 910.94 },
+        { 235200616933000, 590.00, 844.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -8715.686523); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -7639.026367); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast1) {
+    // Sailfish - fling up - fast - 1
+    Position values[] = {
+        { 920922149000, 561.00, 1412.00 },
+        { 920930185000, 559.00, 1377.00 },
+        { 920930262463, 558.98, 1376.66 },
+        { 920938547000, 559.00, 1371.00 },
+        { 920947096857, 562.91, 1342.68 },
+        { 920947302000, 563.00, 1342.00 },
+        { 920955502000, 577.00, 1272.00 },
+        { 920963931021, 596.87, 1190.54 },
+        { 920963987000, 597.00, 1190.00 },
+        { 920972530000, 631.00, 1093.00 },
+        { 920980765511, 671.31, 994.68 },
+        { 920980906000, 672.00, 993.00 },
+        { 920989261000, 715.00, 903.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5670.329102); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 5991.866699); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -13021.101562); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -15093.995117); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast2) {
+    // Sailfish - fling up - fast - 2
+    Position values[] = {
+        { 235247153233000, 518.00, 1168.00 },
+        { 235247170452000, 517.00, 1167.00 },
+        { 235247178908000, 515.00, 1159.00 },
+        { 235247179556213, 514.85, 1158.39 },
+        { 235247186821000, 515.00, 1125.00 },
+        { 235247195265000, 521.00, 1051.00 },
+        { 235247196389476, 521.80, 1041.15 },
+        { 235247203649000, 538.00, 932.00 },
+        { 235247212253000, 571.00, 794.00 },
+        { 235247213222491, 574.72, 778.45 },
+        { 235247220736000, 620.00, 641.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20286.958984); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -20494.587891); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingUpFast3) {
+    // Sailfish - fling up - fast - 3
+    Position values[] = {
+        { 235302568736000, 529.00, 1167.00 },
+        { 235302576644000, 523.00, 1140.00 },
+        { 235302579395063, 520.91, 1130.61 },
+        { 235302585140000, 522.00, 1130.00 },
+        { 235302593615000, 527.00, 1065.00 },
+        { 235302596207444, 528.53, 1045.12 },
+        { 235302602102000, 559.00, 872.00 },
+        { 235302610545000, 652.00, 605.00 },
+        { 235302613019881, 679.26, 526.73 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -39295.941406); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, -36461.421875); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow1) {
+    // Sailfish - fling down - slow - 1
+    Position values[] = {
+        { 235655749552755, 582.00, 432.49 },
+        { 235655750638000, 582.00, 433.00 },
+        { 235655758865000, 582.00, 440.00 },
+        { 235655766221523, 581.16, 448.43 },
+        { 235655767594000, 581.00, 450.00 },
+        { 235655776044000, 580.00, 462.00 },
+        { 235655782890696, 579.18, 474.35 },
+        { 235655784360000, 579.00, 477.00 },
+        { 235655792795000, 578.00, 496.00 },
+        { 235655799559531, 576.27, 515.04 },
+        { 235655800612000, 576.00, 518.00 },
+        { 235655809535000, 574.00, 542.00 },
+        { 235655816988015, 572.17, 564.86 },
+        { 235655817685000, 572.00, 567.00 },
+        { 235655825981000, 569.00, 595.00 },
+        { 235655833808653, 566.26, 620.60 },
+        { 235655834541000, 566.00, 623.00 },
+        { 235655842893000, 563.00, 649.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -419.749695); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -398.303894); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3309.016357); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3969.099854); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow2) {
+    // Sailfish - fling down - slow - 2
+    Position values[] = {
+        { 235671152083370, 485.24, 558.28 },
+        { 235671154126000, 485.00, 559.00 },
+        { 235671162497000, 484.00, 566.00 },
+        { 235671168750511, 483.27, 573.29 },
+        { 235671171071000, 483.00, 576.00 },
+        { 235671179390000, 482.00, 588.00 },
+        { 235671185417210, 481.31, 598.98 },
+        { 235671188173000, 481.00, 604.00 },
+        { 235671196371000, 480.00, 624.00 },
+        { 235671202084196, 479.27, 639.98 },
+        { 235671204235000, 479.00, 646.00 },
+        { 235671212554000, 478.00, 673.00 },
+        { 235671219471011, 476.39, 697.12 },
+        { 235671221159000, 476.00, 703.00 },
+        { 235671229592000, 474.00, 734.00 },
+        { 235671236281462, 472.43, 758.38 },
+        { 235671238098000, 472.00, 765.00 },
+        { 235671246532000, 470.00, 799.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -262.80426); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -243.665344); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4215.682129); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4587.986816); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownSlow3) {
+    // Sailfish - fling down - slow - 3
+    Position values[] = {
+        { 170983201000, 557.00, 533.00 },
+        { 171000668000, 556.00, 534.00 },
+        { 171007359750, 554.73, 535.27 },
+        { 171011197000, 554.00, 536.00 },
+        { 171017660000, 552.00, 540.00 },
+        { 171024201831, 549.97, 544.73 },
+        { 171027333000, 549.00, 547.00 },
+        { 171034603000, 545.00, 557.00 },
+        { 171041043371, 541.98, 567.55 },
+        { 171043147000, 541.00, 571.00 },
+        { 171051052000, 536.00, 586.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -723.413513); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -651.038452); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 2091.502441); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 1934.517456); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster1) {
+    // Sailfish - fling down - faster - 1
+    Position values[] = {
+        { 235695280333000, 558.00, 451.00 },
+        { 235695283971237, 558.43, 454.45 },
+        { 235695289038000, 559.00, 462.00 },
+        { 235695297388000, 561.00, 478.00 },
+        { 235695300638465, 561.83, 486.25 },
+        { 235695305265000, 563.00, 498.00 },
+        { 235695313591000, 564.00, 521.00 },
+        { 235695317305492, 564.43, 532.68 },
+        { 235695322181000, 565.00, 548.00 },
+        { 235695330709000, 565.00, 577.00 },
+        { 235695333972227, 565.00, 588.10 },
+        { 235695339250000, 565.00, 609.00 },
+        { 235695347839000, 565.00, 642.00 },
+        { 235695351313257, 565.00, 656.18 },
+        { 235695356412000, 565.00, 677.00 },
+        { 235695364899000, 563.00, 710.00 },
+        { 235695368118682, 562.24, 722.52 },
+        { 235695373403000, 564.00, 744.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4254.639648); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4698.415039); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster2) {
+    // Sailfish - fling down - faster - 2
+    Position values[] = {
+        { 235709624766000, 535.00, 579.00 },
+        { 235709642256000, 534.00, 580.00 },
+        { 235709643350278, 533.94, 580.06 },
+        { 235709650760000, 532.00, 584.00 },
+        { 235709658615000, 530.00, 593.00 },
+        { 235709660170495, 529.60, 594.78 },
+        { 235709667095000, 527.00, 606.00 },
+        { 235709675616000, 524.00, 628.00 },
+        { 235709676983261, 523.52, 631.53 },
+        { 235709684289000, 521.00, 652.00 },
+        { 235709692763000, 518.00, 682.00 },
+        { 235709693804993, 517.63, 685.69 },
+        { 235709701438000, 515.00, 709.00 },
+        { 235709709830000, 512.00, 739.00 },
+        { 235709710626776, 511.72, 741.85 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -430.440247); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -447.600311); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 3953.859375); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4316.155273); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFaster3) {
+    // Sailfish - fling down - faster - 3
+    Position values[] = {
+        { 235727628927000, 540.00, 440.00 },
+        { 235727636810000, 537.00, 454.00 },
+        { 235727646176000, 536.00, 454.00 },
+        { 235727653586628, 535.12, 456.65 },
+        { 235727654557000, 535.00, 457.00 },
+        { 235727663024000, 534.00, 465.00 },
+        { 235727670410103, 533.04, 479.45 },
+        { 235727670691000, 533.00, 480.00 },
+        { 235727679255000, 531.00, 501.00 },
+        { 235727687233704, 529.09, 526.73 },
+        { 235727687628000, 529.00, 528.00 },
+        { 235727696113000, 526.00, 558.00 },
+        { 235727704057546, 523.18, 588.98 },
+        { 235727704576000, 523.00, 591.00 },
+        { 235727713099000, 520.00, 626.00 },
+        { 235727720880776, 516.33, 655.36 },
+        { 235727721580000, 516.00, 658.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4484.617676); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 4927.92627); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast1) {
+    // Sailfish - fling down - fast - 1
+    Position values[] = {
+        { 235762352849000, 467.00, 286.00 },
+        { 235762360250000, 443.00, 344.00 },
+        { 235762362787412, 434.77, 363.89 },
+        { 235762368807000, 438.00, 359.00 },
+        { 235762377220000, 425.00, 423.00 },
+        { 235762379608561, 421.31, 441.17 },
+        { 235762385698000, 412.00, 528.00 },
+        { 235762394133000, 406.00, 648.00 },
+        { 235762396429369, 404.37, 680.67 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 19084.931641); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16064.685547); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast2) {
+    // Sailfish - fling down - fast - 2
+    Position values[] = {
+        { 235772487188000, 576.00, 204.00 },
+        { 235772495159000, 553.00, 236.00 },
+        { 235772503568000, 551.00, 240.00 },
+        { 235772508192247, 545.55, 254.17 },
+        { 235772512051000, 541.00, 266.00 },
+        { 235772520794000, 520.00, 337.00 },
+        { 235772525015263, 508.92, 394.43 },
+        { 235772529174000, 498.00, 451.00 },
+        { 235772537635000, 484.00, 589.00 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 18660.048828); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 16918.439453); // lsq2
+}
+
+
+TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) {
+    // Sailfish - fling down - fast - 3
+    Position values[] = {
+        { 507650295000, 628.00, 233.00 },
+        { 507658234000, 605.00, 269.00 },
+        { 507666784000, 601.00, 274.00 },
+        { 507669660483, 599.65, 275.68 },
+        { 507675427000, 582.00, 308.00 },
+        { 507683740000, 541.00, 404.00 },
+        { 507686506238, 527.36, 435.95 },
+        { 507692220000, 487.00, 581.00 },
+        { 507700707000, 454.00, 792.00 },
+        { 507703352649, 443.71, 857.77 },
+    };
+    size_t count = sizeof(values) / sizeof(Position);
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6772.508301); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, -6388.48877); // lsq2
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 29765.908203); // impulse
+    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
+}
+
+
+} // namespace android
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
new file mode 100644
index 0000000..6a38a1f
--- /dev/null
+++ b/libs/sensor/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+pengxu@google.com
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index cf79762..a610a51 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -47,7 +47,7 @@
     ],
 
     sanitize: {
-        //misc_undefined: ["integer"],
+        integer_overflow: true,
     },
 
     srcs: [
@@ -74,6 +74,7 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
         "libbase",
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 0eb08e5..1f746a2 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -39,9 +39,15 @@
 Mapper::Mapper()
 {
     mMapper = IMapper::getService();
-    if (mMapper == nullptr || mMapper->isRemote()) {
+    if (mMapper == nullptr) {
+        LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+    }
+    if (mMapper->isRemote()) {
         LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
     }
+
+    // IMapper 2.1 is optional
+    mMapperV2_1 = hardware::graphics::mapper::V2_1::IMapper::castFrom(mMapper);
 }
 
 Error Mapper::createDescriptor(
@@ -91,6 +97,50 @@
             buffer, error);
 }
 
+Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
+        const IMapper::BufferDescriptorInfo& descriptorInfo,
+        uint32_t stride) const
+{
+    if (mMapperV2_1 == nullptr) {
+        return Error::NONE;
+    }
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
+
+    return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+}
+
+void Mapper::getTransportSize(buffer_handle_t bufferHandle,
+        uint32_t* outNumFds, uint32_t* outNumInts) const
+{
+    *outNumFds = uint32_t(bufferHandle->numFds);
+    *outNumInts = uint32_t(bufferHandle->numInts);
+
+    if (mMapperV2_1 == nullptr) {
+        return;
+    }
+
+    Error error;
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->getTransportSize(buffer,
+            [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outNumFds = tmpNumFds;
+                *outNumInts = tmpNumInts;
+            });
+
+    if (!ret.isOk()) {
+        error = kTransactionError;
+    }
+    ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
+            buffer, error);
+}
+
 Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
         const IMapper::Rect& accessRegion,
         int acquireFence, void** outData) const
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c880500..4ed2aa4 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -170,6 +170,8 @@
             inUsage, &handle, &outStride, mId,
             std::move(requestorName));
     if (err == NO_ERROR) {
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
         format = inFormat;
@@ -199,7 +201,8 @@
 
     if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, width, height,
+                layerCount, format, usage, stride, &importedHandle);
         if (err != NO_ERROR) {
             initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
 
@@ -212,6 +215,7 @@
         }
 
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     ANativeWindowBuffer::handle = handle;
@@ -323,11 +327,11 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
-    return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int);
+    return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
-    return static_cast<size_t>(handle ? handle->numFds : 0);
+    return static_cast<size_t>(handle ? mTransportNumFds : 0);
 }
 
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
@@ -353,18 +357,18 @@
     buf[12] = int(usage >> 32); // high 32-bits
 
     if (handle) {
-        buf[10] = handle->numFds;
-        buf[11] = handle->numInts;
-        memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int));
+        buf[10] = int32_t(mTransportNumFds);
+        buf[11] = int32_t(mTransportNumInts);
+        memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
         memcpy(buf + 13, handle->data + handle->numFds,
-                static_cast<size_t>(handle->numInts) * sizeof(int));
+                static_cast<size_t>(mTransportNumInts) * sizeof(int));
     }
 
     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
     size -= sizeNeeded;
     if (handle) {
-        fds += handle->numFds;
-        count -= static_cast<size_t>(handle->numFds);
+        fds += mTransportNumFds;
+        count -= static_cast<size_t>(mTransportNumFds);
     }
 
     return NO_ERROR;
@@ -457,7 +461,8 @@
 
     if (handle != 0) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
+                uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
         if (err != NO_ERROR) {
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
@@ -470,6 +475,7 @@
         native_handle_close(handle);
         native_handle_delete(const_cast<native_handle_t*>(handle));
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index d854489..2cac287 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -52,17 +52,42 @@
 }
 
 status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
+        uint32_t width, uint32_t height, uint32_t layerCount,
+        PixelFormat format, uint64_t usage, uint32_t stride,
         buffer_handle_t* outHandle)
 {
     ATRACE_CALL();
 
+    buffer_handle_t bufferHandle;
     Gralloc2::Error error = mMapper->importBuffer(
-            hardware::hidl_handle(rawHandle), outHandle);
+            hardware::hidl_handle(rawHandle), &bufferHandle);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
+        return static_cast<status_t>(error);
+    }
 
-    ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d",
-            rawHandle, error);
+    Gralloc2::IMapper::BufferDescriptorInfo info = {};
+    info.width = width;
+    info.height = height;
+    info.layerCount = layerCount;
+    info.format = static_cast<Gralloc2::PixelFormat>(format);
+    info.usage = usage;
+    error = mMapper->validateBufferSize(bufferHandle, info, stride);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
+        freeBuffer(bufferHandle);
+        return static_cast<status_t>(error);
+    }
 
-    return static_cast<status_t>(error);
+    *outHandle = bufferHandle;
+
+    return NO_ERROR;
+}
+
+void GraphicBufferMapper::getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts)
+{
+    mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts);
 }
 
 status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle)
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 8aee160..69c35f7 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -21,6 +21,7 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -55,6 +56,13 @@
 
     void freeBuffer(buffer_handle_t bufferHandle) const;
 
+    Error validateBufferSize(buffer_handle_t bufferHandle,
+            const IMapper::BufferDescriptorInfo& descriptorInfo,
+            uint32_t stride) const;
+
+    void getTransportSize(buffer_handle_t bufferHandle,
+            uint32_t* outNumFds, uint32_t* outNumInts) const;
+
     // The ownership of acquireFence is always transferred to the callee, even
     // on errors.
     Error lock(buffer_handle_t bufferHandle, uint64_t usage,
@@ -73,6 +81,7 @@
 
 private:
     sp<IMapper> mMapper;
+    sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
 };
 
 // A wrapper to IAllocator
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 95c2d22..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -230,6 +230,10 @@
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
 
+    // numbers of fds/ints in native_handle_t to flatten
+    uint32_t mTransportNumFds;
+    uint32_t mTransportNumInts;
+
     uint64_t mId;
 
     // Stores the generation number of this buffer. If this number does not
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 06961b1..7cf003d 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -22,6 +22,7 @@
 
 #include <memory>
 
+#include <ui/PixelFormat.h>
 #include <utils/Singleton.h>
 
 
@@ -49,10 +50,15 @@
     // The imported outHandle must be freed with freeBuffer when no longer
     // needed. rawHandle is owned by the caller.
     status_t importBuffer(buffer_handle_t rawHandle,
+            uint32_t width, uint32_t height, uint32_t layerCount,
+            PixelFormat format, uint64_t usage, uint32_t stride,
             buffer_handle_t* outHandle);
 
     status_t freeBuffer(buffer_handle_t handle);
 
+    void getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
+
     status_t lock(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr);
 
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index fb69d5c..44be0ab 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -570,6 +570,9 @@
   // Copy from latest record in shared_config_ring_ to local copy.
   DvrConfig record;
   if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+    ALOGI("DvrConfig updated: sequence %u, post offset %d",
+          shared_config_ring_sequence_, record.frame_post_offset_ns);
+    ++shared_config_ring_sequence_;
     post_thread_config_ = record;
   }
 }
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 1428945..2b76279 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -62,19 +62,10 @@
         return;
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    err = sc->setLayer(0x7FFFFFFF);     // always on top
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
-        return;
-    }
-
-    err = sc->show();
-    if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
-        return;
-    }
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::Transaction{}
+            .setLayer(sc, 0x7FFFFFFF)
+            .show(sc)
+            .apply();
 
     mSurfaceControl = sc;
 }
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f6813fd..66836b5 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -21,7 +21,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 4df61d3..fb75d81 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -21,7 +21,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 7062c57..2163d76 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -1,5 +1,5 @@
 #include <jni.h>
-#include <JNIHelp.h>
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 #include <assert.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 026cb37..03e16e9 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -21,7 +21,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 22b084a..12ad47e 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -3,7 +3,6 @@
 
     srcs: [
         "IAudioManager.cpp",
-        "IPlayer.cpp",
     ],
 
     shared_libs: [
diff --git a/services/audiomanager/IPlayer.cpp b/services/audiomanager/IPlayer.cpp
deleted file mode 100644
index e8a9c34..0000000
--- a/services/audiomanager/IPlayer.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "IPlayer"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <audiomanager/IPlayer.h>
-
-namespace android {
-
-enum {
-    START      = IBinder::FIRST_CALL_TRANSACTION,
-    PAUSE      = IBinder::FIRST_CALL_TRANSACTION + 1,
-    STOP       = IBinder::FIRST_CALL_TRANSACTION + 2,
-    SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3,
-    SET_PAN    = IBinder::FIRST_CALL_TRANSACTION + 4,
-    SET_START_DELAY_MS = IBinder::FIRST_CALL_TRANSACTION + 5,
-    APPLY_VOLUME_SHAPER = IBinder::FIRST_CALL_TRANSACTION + 6,
-};
-
-class BpPlayer : public BpInterface<IPlayer>
-{
-public:
-    explicit BpPlayer(const sp<IBinder>& impl)
-        : BpInterface<IPlayer>(impl)
-    {
-    }
-
-    virtual void start()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        remote()->transact(START, data, &reply);
-    }
-
-    virtual void pause()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        remote()->transact(PAUSE, data, &reply);
-    }
-
-    virtual void stop()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        remote()->transact(STOP, data, &reply);
-    }
-
-    virtual void setVolume(float vol)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        data.writeFloat(vol);
-        remote()->transact(SET_VOLUME, data, &reply);
-    }
-
-    virtual void setPan(float pan)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        data.writeFloat(pan);
-        remote()->transact(SET_PAN, data, &reply);
-    }
-
-    virtual void setStartDelayMs(int32_t delayMs) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-        data.writeInt32(delayMs);
-        remote()->transact(SET_START_DELAY_MS, data, &reply);
-    }
-
-    virtual void applyVolumeShaper(
-            const sp<VolumeShaper::Configuration>& configuration,
-            const sp<VolumeShaper::Operation>& operation) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
-
-        status_t status = configuration.get() == nullptr
-                ? data.writeInt32(0)
-                :  data.writeInt32(1)
-                    ?: configuration->writeToParcel(&data);
-        if (status != NO_ERROR) {
-            ALOGW("applyVolumeShaper failed configuration parceling: %d", status);
-            return; // ignore error
-        }
-
-        status = operation.get() == nullptr
-                ? status = data.writeInt32(0)
-                : data.writeInt32(1)
-                    ?: operation->writeToParcel(&data);
-        if (status != NO_ERROR) {
-            ALOGW("applyVolumeShaper failed operation parceling: %d", status);
-            return; // ignore error
-        }
-
-        status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply);
-
-        ALOGW_IF(status != NO_ERROR, "applyVolumeShaper failed transact: %d", status);
-        return; // one way transaction, ignore error
-    }
-};
-
-IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer");
-
-// ----------------------------------------------------------------------
-
-status_t BnPlayer::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-        case START: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            start();
-            return NO_ERROR;
-        } break;
-        case PAUSE: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            pause();
-            return NO_ERROR;
-        }
-        case STOP: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            stop();
-            return NO_ERROR;
-        } break;
-        case SET_VOLUME: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            setVolume(data.readFloat());
-            return NO_ERROR;
-        } break;
-        case SET_PAN: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            setPan(data.readFloat());
-            return NO_ERROR;
-        } break;
-        case SET_START_DELAY_MS: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            setStartDelayMs(data.readInt32());
-            return NO_ERROR;
-        } break;
-        case APPLY_VOLUME_SHAPER: {
-            CHECK_INTERFACE(IPlayer, data, reply);
-            sp<VolumeShaper::Configuration> configuration;
-            sp<VolumeShaper::Operation> operation;
-
-            int32_t present;
-            status_t status = data.readInt32(&present);
-            if (status == NO_ERROR && present != 0) {
-                configuration = new VolumeShaper::Configuration();
-                status = configuration->readFromParcel(data);
-            }
-            status = status ?: data.readInt32(&present);
-            if (status == NO_ERROR && present != 0) {
-                operation = new VolumeShaper::Operation();
-                status = operation->readFromParcel(data);
-            }
-            if (status == NO_ERROR) {
-                // one way transaction, no error returned
-                applyVolumeShaper(configuration, operation);
-            }
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} // namespace android
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 42f9ba9..0312185 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -685,7 +685,7 @@
 bool InputDispatcher::dispatchConfigurationChangedLocked(
         nsecs_t currentTime, ConfigurationChangedEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime);
+    ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime);
 #endif
 
     // Reset key repeating in case a keyboard device was added or removed or something.
@@ -701,7 +701,8 @@
 bool InputDispatcher::dispatchDeviceResetLocked(
         nsecs_t currentTime, DeviceResetEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId);
+    ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime,
+            entry->deviceId);
 #endif
 
     CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
@@ -811,9 +812,9 @@
 
 void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
-            "repeatCount=%d, downTime=%lld",
+            "repeatCount=%d, downTime=%" PRId64,
             prefix,
             entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
             entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
@@ -884,10 +885,10 @@
 
 void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, actionButton=0x%x, flags=0x%x, "
             "metaState=0x%x, buttonState=0x%x,"
-            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
+            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
             prefix,
             entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
             entry->action, entry->actionButton, entry->flags,
@@ -2231,7 +2232,7 @@
 
     if (!cancelationEvents.isEmpty()) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
+        ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
                 "with reality: %s, mode=%d.",
                 connection->getInputChannelName(), cancelationEvents.size(),
                 options.reason, options.mode);
@@ -2367,7 +2368,7 @@
 
 void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime);
+    ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
 #endif
 
     bool needWake;
@@ -2385,8 +2386,9 @@
 
 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
-            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
+    ALOGD("notifyKey - eventTime=%" PRId64
+            ", deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
+            "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
             args->eventTime, args->deviceId, args->source, args->policyFlags,
             args->action, args->flags, args->keyCode, args->scanCode,
             args->metaState, args->downTime);
@@ -2480,9 +2482,9 @@
 
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
-            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
+            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
             args->eventTime, args->deviceId, args->source, args->policyFlags,
             args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
             args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
@@ -2560,9 +2562,9 @@
 
 void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x",
-            args->eventTime, args->policyFlags,
-            args->switchValues, args->switchMask);
+    ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
+            "switchMask=0x%08x",
+            args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
 #endif
 
     uint32_t policyFlags = args->policyFlags;
@@ -2573,7 +2575,7 @@
 
 void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d",
+    ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d",
             args->eventTime, args->deviceId);
 #endif
 
@@ -3741,7 +3743,7 @@
                     msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
                             fallbackKeys.valueAt(i));
                 }
-                ALOGD("Unhandled key event: %d currently tracked fallback keys%s.",
+                ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
                         fallbackKeys.size(), msg.string());
             }
 #endif
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index d4266f6..6dd12d6 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -429,7 +429,7 @@
                 batchSize += 1;
             }
 #if DEBUG_RAW_EVENTS
-            ALOGD("BatchSize: %d Count: %d", batchSize, count);
+            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
 #endif
             processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
         } else {
@@ -1176,7 +1176,7 @@
     size_t numMappers = mMappers.size();
     for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
 #if DEBUG_RAW_EVENTS
-        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
+        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
                 rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
                 rawEvent->when);
 #endif
@@ -1851,7 +1851,7 @@
 #if DEBUG_POINTERS
             if (newSlot) {
                 ALOGW("MultiTouch device emitted invalid slot index %d but it "
-                        "should be between 0 and %d; ignoring this slot.",
+                        "should be between 0 and %zd; ignoring this slot.",
                         mCurrentSlot, mSlotCount - 1);
             }
 #endif
@@ -2147,9 +2147,9 @@
         if (i != 0) {
             patternStr.append(", ");
         }
-        patternStr.appendFormat("%lld", pattern[i]);
+        patternStr.appendFormat("%" PRId64, pattern[i]);
     }
-    ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d",
+    ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d",
             getDeviceId(), patternStr.string(), repeat, token);
 #endif
 
@@ -2198,8 +2198,7 @@
     nsecs_t duration = mPattern[mIndex];
     if (vibratorOn) {
 #if DEBUG_VIBRATOR
-        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld",
-                getDeviceId(), duration);
+        ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration);
 #endif
         getEventHub()->vibrate(getDeviceId(), duration);
     } else {
@@ -6631,7 +6630,7 @@
 #if DEBUG_POINTER_ASSIGNMENT
     ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
     for (size_t i = 0; i < heapSize; i++) {
-        ALOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+        ALOGD("  heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
                 i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
                 heap[i].distance);
     }
@@ -6677,7 +6676,7 @@
 #if DEBUG_POINTER_ASSIGNMENT
                 ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
                 for (size_t i = 0; i < heapSize; i++) {
-                    ALOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+                    ALOGD("  heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
                             i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
                             heap[i].distance);
                 }
@@ -6703,7 +6702,8 @@
             usedIdBits.markBit(id);
 
 #if DEBUG_POINTER_ASSIGNMENT
-            ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+            ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32
+                    ", id=%" PRIu32 ", distance=%" PRIu64,
                     lastPointerIndex, currentPointerIndex, id, heap[0].distance);
 #endif
             break;
@@ -6721,8 +6721,7 @@
                 current->rawPointerData.isHovering(currentPointerIndex));
 
 #if DEBUG_POINTER_ASSIGNMENT
-        ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
-                currentPointerIndex, id);
+        ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id);
 #endif
     }
 }
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index a49c8c8..8a35509 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -19,7 +19,6 @@
         "libhardware",
         "libhardware_legacy",
         "libui",
-        "libskia",
         "libinput",
         "libinputflinger",
         "libinputservice",
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
new file mode 100644
index 0000000..6a38a1f
--- /dev/null
+++ b/services/sensorservice/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+pengxu@google.com
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 535d0db..fdb69d3 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -217,8 +217,13 @@
 }
 
 void SensorDevice::autoDisable(void *ident, int handle) {
-    Info& info( mActivationCount.editValueFor(handle) );
     Mutex::Autolock _l(mLock);
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
     info.removeBatchParamsForIdent(ident);
 }
 
@@ -229,7 +234,12 @@
     bool actuateHardware = false;
 
     Mutex::Autolock _l(mLock);
-    Info& info( mActivationCount.editValueFor(handle) );
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return BAD_VALUE;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
 
     ALOGD_IF(DEBUG_CONNECTIONS,
              "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
@@ -323,7 +333,12 @@
              ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
 
     Mutex::Autolock _l(mLock);
-    Info& info(mActivationCount.editValueFor(handle));
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        ALOGW("Handle %d cannot be found in activation record", handle);
+        return BAD_VALUE;
+    }
+    Info& info(mActivationCount.editValueAt(activationIndex));
 
     if (info.batchParams.indexOfKey(ident) < 0) {
         BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 4775e4e..64a2a50 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,6 +1,8 @@
 cc_library_static {
     name: "libsurfaceflingerincludes",
     export_include_dirs: ["."],
+    static_libs = ["libserviceutils"],
+    export_static_lib_headers = ["libserviceutils"],
 }
 
 subdirs = ["tests/fakehwc"]
\ No newline at end of file
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 38529b6..390263f 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -14,7 +14,7 @@
     FrameTracker.cpp \
     GpuService.cpp \
     Layer.cpp \
-    LayerDim.cpp \
+    ColorLayer.cpp \
     LayerRejecter.cpp \
     LayerVector.cpp \
     MessageQueue.cpp \
@@ -67,7 +67,10 @@
     libtrace_proto \
     libvkjson \
     libvr_manager \
-    libvrflinger
+    libvrflinger \
+    libserviceutils
+
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libserviceutils
 
 LOCAL_SHARED_LIBRARIES := \
     android.frameworks.vr.composer@1.0 \
@@ -145,7 +148,8 @@
     libdl
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_STATIC_LIBRARIES := libtrace_proto
+LOCAL_STATIC_LIBRARIES := libtrace_proto \
+    libserviceutils
 
 LOCAL_MODULE := surfaceflinger
 
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 8ba6cb9..ea6541a 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -140,7 +140,8 @@
 {
     sp<Layer> parent = nullptr;
     if (parentHandle != nullptr) {
-        parent = getLayerUser(parentHandle);
+        auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get());
+        parent = layerHandle->owner.promote();
         if (parent == nullptr) {
             return NAME_NOT_FOUND;
         }
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/ColorLayer.cpp
similarity index 79%
rename from services/surfaceflinger/LayerDim.cpp
rename to services/surfaceflinger/ColorLayer.cpp
index daebf8a..6923782 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -16,7 +16,7 @@
 
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
-#define LOG_TAG "LayerDim"
+#define LOG_TAG "ColorLayer"
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -27,7 +27,7 @@
 
 #include <ui/GraphicBuffer.h>
 
-#include "LayerDim.h"
+#include "ColorLayer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayDevice.h"
 #include "RenderEngine/RenderEngine.h"
@@ -35,31 +35,29 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
+ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags)
     : Layer(flinger, client, name, w, h, flags) {
 }
 
-LayerDim::~LayerDim() {
-}
-
-void LayerDim::onDraw(const sp<const DisplayDevice>& hw,
+void ColorLayer::onDraw(const sp<const DisplayDevice>& hw,
         const Region& /* clip */, bool useIdentityTransform) const
 {
     const State& s(getDrawingState());
-    if (s.alpha>0) {
+    if (s.color.a>0) {
         Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
         computeGeometry(hw, mesh, useIdentityTransform);
         RenderEngine& engine(mFlinger->getRenderEngine());
-        engine.setupDimLayerBlending(s.alpha);
+        engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
+              true /* disableTexture */, s.color);
         engine.drawMesh(mesh);
         engine.disableBlending();
     }
 }
 
-bool LayerDim::isVisible() const {
+bool ColorLayer::isVisible() const {
     const Layer::State& s(getDrawingState());
-    return !isHiddenByPolicy() && s.alpha;
+    return !isHiddenByPolicy() && s.color.a;
 }
 
 
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/ColorLayer.h
similarity index 81%
rename from services/surfaceflinger/LayerDim.h
rename to services/surfaceflinger/ColorLayer.h
index a0cfca9..ac3e2a9 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_LAYER_DIM_H
-#define ANDROID_LAYER_DIM_H
+#ifndef ANDROID_COLOR_LAYER_H
+#define ANDROID_COLOR_LAYER_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -26,14 +26,14 @@
 
 namespace android {
 
-class LayerDim : public Layer
+class ColorLayer : public Layer
 {
 public:
-                LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
+    ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client,
                         const String8& name, uint32_t w, uint32_t h, uint32_t flags);
-        virtual ~LayerDim();
+    virtual ~ColorLayer() = default;
 
-    virtual const char* getTypeId() const { return "LayerDim"; }
+    virtual const char* getTypeId() const { return "ColorLayer"; }
     virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
             bool useIdentityTransform) const;
     virtual bool isOpaque(const Layer::State&) const { return false; }
@@ -46,4 +46,4 @@
 
 }; // namespace android
 
-#endif // ANDROID_LAYER_DIM_H
+#endif // ANDROID_COLOR_LAYER_H
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 248ef53..0244c1b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -28,6 +28,7 @@
 #include <utils/RefBase.h>
 #include <utils/Log.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/PixelFormat.h>
 
@@ -617,6 +618,7 @@
 
 void DisplayDevice::dump(String8& result) const {
     const Transform& tr(mGlobalTransform);
+    ANativeWindow* const window = mNativeWindow.get();
     EGLint redSize, greenSize, blueSize, alphaSize;
     eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
     eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
@@ -626,9 +628,9 @@
     result.appendFormat("   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
                         "(%d:%d:%d:%d), orient=%2d (type=%08x), "
                         "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
-                        mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight,
-                        mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation,
-                        tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+                        mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
+                        redSize, greenSize, blueSize, alphaSize, mOrientation, tr.getType(),
+                        getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
                         mVisibleLayersSortedByZ.size());
     result.appendFormat("   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
                         "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
@@ -636,6 +638,9 @@
                         mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
                         mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
                         tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
+    auto const surface = static_cast<Surface*>(window);
+    android_dataspace dataspace = surface->getBuffersDataSpace();
+    result.appendFormat("   dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace);
 
     String8 surfaceDump;
     mDisplaySurface->dumpAsString(surfaceDump);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e92565f..956f7f6 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -137,11 +137,7 @@
     mCurrentState.requestedFinalCrop = mCurrentState.finalCrop;
     mCurrentState.requestedCrop = mCurrentState.crop;
     mCurrentState.z = 0;
-#ifdef USE_HWC2
-    mCurrentState.alpha = 1.0f;
-#else
-    mCurrentState.alpha = 0xFF;
-#endif
+    mCurrentState.color.a = 1.0f;
     mCurrentState.layerStack = 0;
     mCurrentState.flags = layerFlags;
     mCurrentState.sequence = 0;
@@ -334,6 +330,10 @@
     return mName;
 }
 
+bool Layer::getPremultipledAlpha() const {
+    return mPremultipliedAlpha;
+}
+
 status_t Layer::setBuffers( uint32_t w, uint32_t h,
                             PixelFormat format, uint32_t flags)
 {
@@ -683,7 +683,7 @@
              " %s (%d)", mName.string(), to_string(blendMode).c_str(),
              to_string(error).c_str(), static_cast<int32_t>(error));
 #else
-    if (!isOpaque(s) || getAlpha() != 0xFF) {
+    if (!isOpaque(s) || getAlpha() != 1.0f) {
         layer.setBlending(mPremultipliedAlpha ?
                 HWC_BLENDING_PREMULT :
                 HWC_BLENDING_COVERAGE);
@@ -757,7 +757,7 @@
         hwcInfo.sourceCrop = sourceCrop;
     }
 
-    float alpha = getAlpha();
+    float alpha = static_cast<float>(getAlpha());
     error = hwcLayer->setPlaneAlpha(alpha);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
             "%s (%d)", mName.string(), alpha, to_string(error).c_str(),
@@ -787,7 +787,7 @@
     const Transform& tr(hw->getTransform());
     layer.setFrame(tr.transform(frame));
     layer.setCrop(computeCrop(hw));
-    layer.setPlaneAlpha(getAlpha());
+    layer.setPlaneAlpha(static_cast<uint8_t>(std::round(255.0f*getAlpha())));
 #endif
 
     /*
@@ -904,8 +904,11 @@
     if (mActiveBuffer == nullptr) {
         setCompositionType(hwcId, HWC2::Composition::SolidColor);
 
-        // For now, we only support black for DimLayer
-        error = hwcLayer->setColor({0, 0, 0, 255});
+        half4 color = getColor();
+        error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f*color.r)),
+                    static_cast<uint8_t>(std::round(255.0f * color.g)),
+                    static_cast<uint8_t>(std::round(255.0f * color.b)),
+                    255});
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set color: %s (%d)", mName.string(),
                     to_string(error).c_str(), static_cast<int32_t>(error));
@@ -1254,7 +1257,8 @@
     texCoords[3] = vec2(right, 1.0f - top);
 
     RenderEngine& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
+    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s),
+        false /* disableTexture */, getColor());
 #ifdef USE_HWC2
     engine.setSourceDataSpace(mCurrentState.dataSpace);
 #endif
@@ -1687,23 +1691,28 @@
                 c.requested.w, c.requested.h);
     }
 
-    const bool resizePending = (c.requested.w != c.active.w) ||
-            (c.requested.h != c.active.h);
+    // Don't let Layer::doTransaction update the drawing state
+    // if we have a pending resize, unless we are in fixed-size mode.
+    // the drawing state will be updated only once we receive a buffer
+    // with the correct size.
+    //
+    // In particular, we want to make sure the clip (which is part
+    // of the geometry state) is latched together with the size but is
+    // latched immediately when no resizing is involved.
+    //
+    // If a sideband stream is attached, however, we want to skip this
+    // optimization so that transactions aren't missed when a buffer
+    // never arrives
+    //
+    // In the case that we don't have a buffer we ignore other factors
+    // and avoid entering the resizePending state. At a high level the
+    // resizePending state is to avoid applying the state of the new buffer
+    // to the old buffer. However in the state where we don't have an old buffer
+    // there is no such concern but we may still be being used as a parent layer.
+    const bool resizePending = ((c.requested.w != c.active.w) ||
+            (c.requested.h != c.active.h)) && (mActiveBuffer != nullptr);
     if (!isFixedSize()) {
         if (resizePending && mSidebandStream == NULL) {
-            // don't let Layer::doTransaction update the drawing state
-            // if we have a pending resize, unless we are in fixed-size mode.
-            // the drawing state will be updated only once we receive a buffer
-            // with the correct size.
-            //
-            // in particular, we want to make sure the clip (which is part
-            // of the geometry state) is latched together with the size but is
-            // latched immediately when no resizing is involved.
-            //
-            // If a sideband stream is attached, however, we want to skip this
-            // optimization so that transactions aren't missed when a buffer
-            // never arrives
-
             flags |= eDontUpdateGeometryState;
         }
     }
@@ -1877,19 +1886,30 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-#ifdef USE_HWC2
 bool Layer::setAlpha(float alpha) {
-#else
-bool Layer::setAlpha(uint8_t alpha) {
-#endif
-    if (mCurrentState.alpha == alpha)
+    if (mCurrentState.color.a == alpha)
         return false;
     mCurrentState.sequence++;
-    mCurrentState.alpha = alpha;
+    mCurrentState.color.a = alpha;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+
+bool Layer::setColor(const half3& color) {
+    if (color.r == mCurrentState.color.r && color.g == mCurrentState.color.g
+        && color.b == mCurrentState.color.b)
+        return false;
+
+    mCurrentState.sequence++;
+    mCurrentState.color.r = color.r;
+    mCurrentState.color.g = color.g;
+    mCurrentState.color.b = color.b;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
     mCurrentState.sequence++;
     mCurrentState.requested.transform.set(
@@ -2141,13 +2161,8 @@
 }
 
 bool Layer::isVisible() const {
-#ifdef USE_HWC2
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f
             && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#else
-    return !(isHiddenByPolicy()) && getAlpha()
-            && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#endif
 }
 
 bool Layer::allTransactionsSignaled() {
@@ -2439,7 +2454,7 @@
     info.mHeight = ds.active.h;
     info.mCrop = ds.crop;
     info.mFinalCrop = ds.finalCrop;
-    info.mAlpha = ds.alpha;
+    info.mColor = ds.color;
     info.mFlags = ds.flags;
     info.mPixelFormat = getPixelFormat();
     info.mDataSpace = getDataSpace();
@@ -2467,7 +2482,6 @@
     info.mContentDirty = contentDirty;
     return info;
 }
-
 #ifdef USE_HWC2
 void Layer::miniDumpHeader(String8& result) {
     result.append("----------------------------------------");
@@ -2501,7 +2515,7 @@
 
     const Layer::State& layerState(getDrawingState());
     const HWCInfo& hwcInfo = mHwcLayers.at(hwcId);
-    result.appendFormat("  %10u | ", layerState.z);
+    result.appendFormat("  %10d | ", layerState.z);
     result.appendFormat("%10s | ",
             to_string(getCompositionType(hwcId)).c_str());
     const Rect& frame = hwcInfo.displayFrame;
@@ -2625,14 +2639,43 @@
     return true;
 }
 
+bool Layer::reparent(const sp<IBinder>& newParentHandle) {
+    if (newParentHandle == nullptr) {
+        return false;
+    }
+
+    auto handle = static_cast<Handle*>(newParentHandle.get());
+    sp<Layer> newParent = handle->owner.promote();
+    if (newParent == nullptr) {
+        ALOGE("Unable to promote Layer handle");
+        return false;
+    }
+
+    sp<Layer> parent = getParent();
+    if (parent != nullptr) {
+        parent->removeChild(this);
+    }
+    newParent->addChild(this);
+
+    sp<Client> client(mClientRef.promote());
+    sp<Client> newParentClient(newParent->mClientRef.promote());
+
+    if (client != newParentClient) {
+        client->setParentLayer(newParent);
+    }
+
+    return true;
+}
+
 bool Layer::detachChildren() {
     traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* child) {
         if (child == this) {
             return;
         }
 
+        sp<Client> parentClient = mClientRef.promote();
         sp<Client> client(child->mClientRef.promote());
-        if (client != nullptr) {
+        if (client != nullptr && parentClient != client) {
             client->detachLayer(child);
         }
     });
@@ -2762,23 +2805,17 @@
     return t * getDrawingState().active.transform;
 }
 
-#ifdef USE_HWC2
-float Layer::getAlpha() const {
+half Layer::getAlpha() const {
     const auto& p = mDrawingParent.promote();
 
-    float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
-    return parentAlpha * getDrawingState().alpha;
+    half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
+    return parentAlpha * getDrawingState().color.a;
 }
-#else
-uint8_t Layer::getAlpha() const {
-    const auto& p = mDrawingParent.promote();
 
-    float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
-    float drawingAlpha = getDrawingState().alpha / 255.0f;
-    drawingAlpha = drawingAlpha * parentAlpha;
-    return static_cast<uint8_t>(std::round(drawingAlpha * 255));
+half4 Layer::getColor() const {
+    const half4 color(getDrawingState().color);
+    return half4(color.r, color.g, color.b, getAlpha());
 }
-#endif
 
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f7b82e4..47924ae 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -33,8 +33,7 @@
 #include <ui/Region.h>
 
 #include <gui/ISurfaceComposerClient.h>
-
-#include <private/gui/LayerState.h>
+#include <gui/LayerState.h>
 
 #include <list>
 
@@ -51,6 +50,8 @@
 #include "RenderEngine/Mesh.h"
 #include "RenderEngine/Texture.h"
 
+#include <math/vec4.h>
+
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -119,11 +120,6 @@
         // to achieve mirroring.
         uint32_t layerStack;
 
-#ifdef USE_HWC2
-        float alpha;
-#else
-        uint8_t alpha;
-#endif
         uint8_t flags;
         uint8_t mask;
         uint8_t reserved[2];
@@ -158,6 +154,8 @@
 
         // A list of surfaces whose Z-order is interpreted relative to ours.
         SortedVector<wp<Layer>> zOrderRelatives;
+
+        half4 color;
     };
 
     // -----------------------------------------------------------------------
@@ -225,11 +223,8 @@
     bool setLayer(int32_t z);
     bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
 
-#ifdef USE_HWC2
     bool setAlpha(float alpha);
-#else
-    bool setAlpha(uint8_t alpha);
-#endif
+    bool setColor(const half3& color);
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setLayerStack(uint32_t layerStack);
@@ -241,6 +236,7 @@
     bool setOverrideScalingMode(int32_t overrideScalingMode);
     void setInfo(uint32_t type, uint32_t appId);
     bool reparentChildren(const sp<IBinder>& layer);
+    bool reparent(const sp<IBinder>& newParentHandle);
     bool detachChildren();
 
     // If we have received a new buffer this frame, we will pass its surface
@@ -508,11 +504,8 @@
     // Returns the Alpha of the Surface, accounting for the Alpha
     // of parent Surfaces in the hierarchy (alpha's will be multiplied
     // down the hierarchy).
-#ifdef USE_HWC2
-    float getAlpha() const;
-#else
-    uint8_t getAlpha() const;
-#endif
+    half getAlpha() const;
+    half4 getColor() const;
 
     void traverseInReverseZOrder(LayerVector::StateSet stateSet,
                                  const LayerVector::Visitor& visitor);
@@ -682,9 +675,8 @@
     sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
     void notifyAvailableFrames();
-
     PixelFormat getPixelFormat() const { return mFormat; }
-
+    bool getPremultipledAlpha() const;
 private:
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index effd319..706960c 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -27,22 +27,15 @@
 namespace android {
 
 Description::Description() {
-    mPlaneAlpha = 1.0f;
     mPremultipliedAlpha = false;
     mOpaque = true;
     mTextureEnabled = false;
     mColorMatrixEnabled = false;
-
-    memset(mColor, 0, sizeof(mColor));
 }
 
 Description::~Description() {
 }
 
-void Description::setPlaneAlpha(GLclampf planeAlpha) {
-    mPlaneAlpha = planeAlpha;
-}
-
 void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
     mPremultipliedAlpha = premultipliedAlpha;
 }
@@ -60,11 +53,8 @@
     mTextureEnabled = false;
 }
 
-void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
-    mColor[0] = red;
-    mColor[1] = green;
-    mColor[2] = blue;
-    mColor[3] = alpha;
+void Description::setColor(const half4& color) {
+    mColor = color;
 }
 
 void Description::setProjectionMatrix(const mat4& mtx) {
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 3beffdf..cbac855 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -35,8 +35,6 @@
     friend class Program;
     friend class ProgramCache;
 
-    // value of the plane-alpha, between 0 and 1
-    GLclampf mPlaneAlpha;
     // whether textures are premultiplied
     bool mPremultipliedAlpha;
     // whether this layer is marked as opaque
@@ -46,8 +44,8 @@
     Texture mTexture;
     bool mTextureEnabled;
 
-    // color used when texturing is disabled
-    GLclampf mColor[4];
+    // color used when texturing is disabled or when setting alpha.
+    half4 mColor;
     // projection matrix
     mat4 mProjectionMatrix;
 
@@ -60,12 +58,11 @@
     Description();
     ~Description();
 
-    void setPlaneAlpha(GLclampf planeAlpha);
     void setPremultipliedAlpha(bool premultipliedAlpha);
     void setOpaque(bool opaque);
     void setTexture(const Texture& texture);
     void disableTexture();
-    void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void setColor(const half4& color);
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
     const mat4& getColorMatrix() const;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 37a530b..daaa11e 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -204,25 +204,17 @@
     mVpHeight = vph;
 }
 
-#ifdef USE_HWC2
 void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
-        bool opaque, float alpha) {
-#else
-void GLES20RenderEngine::setupLayerBlending(
-    bool premultipliedAlpha, bool opaque, int alpha) {
-#endif
-
+        bool opaque, bool disableTexture, const half4& color) {
     mState.setPremultipliedAlpha(premultipliedAlpha);
     mState.setOpaque(opaque);
-#ifdef USE_HWC2
-    mState.setPlaneAlpha(alpha);
+    mState.setColor(color);
 
-    if (alpha < 1.0f || !opaque) {
-#else
-    mState.setPlaneAlpha(alpha / 255.0f);
+    if (disableTexture) {
+        mState.disableTexture();
+    }
 
-    if (alpha < 0xFF || !opaque) {
-#endif
+    if (color.a < 1.0f || !opaque) {
         glEnable(GL_BLEND);
         glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     } else {
@@ -231,33 +223,6 @@
 }
 
 #ifdef USE_HWC2
-void GLES20RenderEngine::setupDimLayerBlending(float alpha) {
-#else
-void GLES20RenderEngine::setupDimLayerBlending(int alpha) {
-#endif
-    mState.setPlaneAlpha(1.0f);
-    mState.setPremultipliedAlpha(true);
-    mState.setOpaque(false);
-#ifdef USE_HWC2
-    mState.setColor(0, 0, 0, alpha);
-#else
-    mState.setColor(0, 0, 0, alpha/255.0f);
-#endif
-    mState.disableTexture();
-
-#ifdef USE_HWC2
-    if (alpha == 1.0f) {
-#else
-    if (alpha == 0xFF) {
-#endif
-        glDisable(GL_BLEND);
-    } else {
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-    }
-}
-
-#ifdef USE_HWC2
 void GLES20RenderEngine::setColorMode(android_color_mode mode) {
     ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
 
@@ -355,10 +320,9 @@
 }
 
 void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
-    mState.setPlaneAlpha(1.0f);
     mState.setPremultipliedAlpha(true);
     mState.setOpaque(false);
-    mState.setColor(r, g, b, a);
+    mState.setColor(half4(r, g, b, a));
     mState.disableTexture();
     glDisable(GL_BLEND);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index eaf94af..5ac12fc 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -68,10 +68,9 @@
     virtual void setViewportAndProjection(size_t vpw, size_t vph,
             Rect sourceCrop, size_t hwh, bool yswap,
             Transform::orientation_flags rotation);
-#ifdef USE_HWC2
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            float alpha) override;
-    virtual void setupDimLayerBlending(float alpha) override;
+            bool disableTexture, const half4& color) override;
+#ifdef USE_HWC2
 
     // Color management related functions and state
     void setColorMode(android_color_mode mode);
@@ -92,10 +91,6 @@
 
     // Currently only supporting sRGB and DisplayP3 color spaces
     mat4 mSrgbToDisplayP3;
-#else
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            int alpha);
-    virtual void setupDimLayerBlending(int alpha);
 #endif
     bool mPlatformHasWideColor = false;
 
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 48a8da5..bd2188b 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -22,6 +22,7 @@
 #include "Program.h"
 #include "ProgramCache.h"
 #include "Description.h"
+#include <math/mat4.h>
 
 namespace android {
 
@@ -63,7 +64,6 @@
         mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
         mSamplerLoc = glGetUniformLocation(programId, "sampler");
         mColorLoc = glGetUniformLocation(programId, "color");
-        mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
 
         // set-up the default values for our uniforms
         glUseProgram(programId);
@@ -132,11 +132,9 @@
         glUniform1i(mSamplerLoc, 0);
         glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray());
     }
-    if (mAlphaPlaneLoc >= 0) {
-        glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha);
-    }
     if (mColorLoc >= 0) {
-        glUniform4fv(mColorLoc, 1, desc.mColor);
+        const float color[4] = {desc.mColor.r, desc.mColor.g, desc.mColor.b, desc.mColor.a};
+        glUniform4fv(mColorLoc, 1, color);
     }
     if (mColorMatrixLoc >= 0) {
         glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index 36bd120..a2ae2ee 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -79,9 +79,6 @@
     /* location of the sampler uniform */
     GLint mSamplerLoc;
 
-    /* location of the alpha plane uniform */
-    GLint mAlphaPlaneLoc;
-
     /* location of the color uniform */
     GLint mColorLoc;
 };
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 06b2252..b437545 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -89,7 +89,7 @@
 void ProgramCache::primeCache() {
     uint32_t shaderCount = 0;
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
-                       Key::PLANE_ALPHA_MASK | Key::TEXTURE_MASK;
+                       Key::ALPHA_MASK | Key::TEXTURE_MASK;
     // Prime the cache for all combinations of the above masks,
     // leaving off the experimental color matrix mask options.
 
@@ -122,8 +122,8 @@
             description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
             description.mTexture.getTextureTarget() == GL_TEXTURE_2D           ? Key::TEXTURE_2D :
             Key::TEXTURE_OFF)
-    .set(Key::PLANE_ALPHA_MASK,
-            (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
+    .set(Key::ALPHA_MASK,
+            (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
     .set(Key::BLEND_MASK,
             description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
     .set(Key::OPACITY_MASK,
@@ -168,12 +168,12 @@
     } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
         fs << "uniform sampler2D sampler;"
            << "varying vec2 outTexCoords;";
-    } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
+    }
+
+    if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
         fs << "uniform vec4 color;";
     }
-    if (needs.hasPlaneAlpha()) {
-        fs << "uniform float alphaPlane;";
-    }
+
     if (needs.hasColorMatrix()) {
         fs << "uniform mat4 colorMatrix;";
     }
@@ -225,18 +225,19 @@
     if (needs.isTexturing()) {
         fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
     } else {
-        fs << "gl_FragColor = color;";
+        fs << "gl_FragColor.rgb = color.rgb;";
+        fs << "gl_FragColor.a = 1.0;";
     }
     if (needs.isOpaque()) {
         fs << "gl_FragColor.a = 1.0;";
     }
-    if (needs.hasPlaneAlpha()) {
-        // modulate the alpha value with planeAlpha
+    if (needs.hasAlpha()) {
+        // modulate the current alpha value with alpha set
         if (needs.isPremultiplied()) {
             // ... and the color too if we're premultiplied
-            fs << "gl_FragColor *= alphaPlane;";
+            fs << "gl_FragColor *= color.a;";
         } else {
-            fs << "gl_FragColor.a *= alphaPlane;";
+            fs << "gl_FragColor.a *= color.a;";
         }
     }
 
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 5b0fbcd..ff5cf0f 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -57,9 +57,9 @@
             OPACITY_TRANSLUCENT     =       0x00000000,
             OPACITY_MASK            =       0x00000002,
 
-            PLANE_ALPHA_LT_ONE      =       0x00000004,
-            PLANE_ALPHA_EQ_ONE      =       0x00000000,
-            PLANE_ALPHA_MASK        =       0x00000004,
+            ALPHA_LT_ONE            =       0x00000004,
+            ALPHA_EQ_ONE            =       0x00000000,
+            ALPHA_MASK              =       0x00000004,
 
             TEXTURE_OFF             =       0x00000000,
             TEXTURE_EXT             =       0x00000008,
@@ -95,8 +95,8 @@
         inline bool isOpaque() const {
             return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
         }
-        inline bool hasPlaneAlpha() const {
-            return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE;
+        inline bool hasAlpha() const {
+            return (mKey & ALPHA_MASK) == ALPHA_LT_ONE;
         }
         inline bool hasColorMatrix() const {
             return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 9544579..fa65979 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -25,6 +25,7 @@
 #include <EGL/eglext.h>
 #include <math/mat4.h>
 #include <Transform.h>
+#include <gui/SurfaceControl.h>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -98,16 +99,13 @@
     virtual void checkErrors() const;
     virtual void setViewportAndProjection(size_t vpw, size_t vph,
             Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0;
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+            bool disableTexture, const half4& color) = 0;
 #ifdef USE_HWC2
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0;
-    virtual void setupDimLayerBlending(float alpha) = 0;
     virtual void setColorMode(android_color_mode mode) = 0;
     virtual void setSourceDataSpace(android_dataspace source) = 0;
     virtual void setWideColor(bool hasWideColor) = 0;
     virtual bool usesWideColor() = 0;
-#else
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
-    virtual void setupDimLayerBlending(int alpha) = 0;
 #endif
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 78ec4fd..5982422 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -73,7 +73,7 @@
 #include "EventThread.h"
 #include "Layer.h"
 #include "LayerVector.h"
-#include "LayerDim.h"
+#include "ColorLayer.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 
@@ -1746,7 +1746,7 @@
 
     // rebuild the visible layer list per screen
     if (CC_UNLIKELY(mVisibleRegionsDirty)) {
-        ATRACE_CALL();
+        ATRACE_NAME("rebuildLayerStacks VR Dirty");
         mVisibleRegionsDirty = false;
         invalidateHwcGeometry();
 
@@ -2444,7 +2444,7 @@
 
                 // compute the opaque region
                 const int32_t layerOrientation = tr.getOrientation();
-                if (s.alpha == 1.0f && !translucent &&
+                if (layer->getAlpha() == 1.0f && !translucent &&
                         ((layerOrientation & Transform::ROT_INVALID) == false)) {
                     // the opaque region is the layer's footprint
                     opaqueRegion = visibleRegion;
@@ -2732,7 +2732,7 @@
                     case HWC2::Composition::SolidColor: {
                         const Layer::State& state(layer->getDrawingState());
                         if (layer->getClearClientTarget(hwcId) && !firstLayer &&
-                                layer->isOpaque(state) && (state.alpha == 1.0f)
+                                layer->isOpaque(state) && (state.color.a == 1.0f)
                                 && hasClientComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
@@ -2795,7 +2795,14 @@
         if (parent == nullptr) {
             mCurrentState.layersSortedByZ.add(lbc);
         } else {
-            if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
+            bool found = false;
+            mCurrentState.traverseInZOrder([&](Layer* layer) {
+                if (layer == parent.get()) {
+                    found = true;
+                }
+            });
+
+            if (!found) {
                 ALOGE("addClientLayer called with a removed parent");
                 return NAME_NOT_FOUND;
             }
@@ -3065,6 +3072,10 @@
             if (layer->setAlpha(s.alpha))
                 flags |= eTraversalNeeded;
         }
+        if (what & layer_state_t::eColorChanged) {
+            if (layer->setColor(s.color))
+                flags |= eTraversalNeeded;
+        }
         if (what & layer_state_t::eMatrixChanged) {
             if (layer->setMatrix(s.matrix))
                 flags |= eTraversalNeeded;
@@ -3121,6 +3132,11 @@
             // We don't trigger a traversal here because if no other state is
             // changed, we don't want this to cause any more work
         }
+        if (what & layer_state_t::eReparent) {
+            if (layer->reparent(s.parentHandleForChild)) {
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
+        }
         if (what & layer_state_t::eReparentChildren) {
             if (layer->reparentChildren(s.reparentHandle)) {
                 flags |= eTransactionNeeded|eTraversalNeeded;
@@ -3163,8 +3179,8 @@
                     uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
-        case ISurfaceComposerClient::eFXSurfaceDim:
-            result = createDimLayer(client,
+        case ISurfaceComposerClient::eFXSurfaceColor:
+            result = createColorLayer(client,
                     uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
@@ -3246,11 +3262,11 @@
     return err;
 }
 
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
 {
-    *outLayer = new LayerDim(this, client, name, w, h, flags);
+    *outLayer = new ColorLayer(this, client, name, w, h, flags);
     *handle = (*outLayer)->getHandle();
     *gbp = (*outLayer)->getProducer();
     return NO_ERROR;
@@ -3443,8 +3459,7 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args) {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
@@ -4589,7 +4604,7 @@
                     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, state.alpha);
+                            layer->isVisible(), state.flags, static_cast<float>(state.color.a));
                     i++;
                 });
             }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1b77aaf..2cba500 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -43,13 +43,15 @@
 #include <gui/FrameTimestamps.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+
 #include <gui/OccupancyTracker.h>
 
 #include <hardware/hwcomposer_defs.h>
 
-#include <system/graphics.h>
+#include <serviceutils/PriorityDumper.h>
 
-#include <private/gui/LayerState.h>
+#include <system/graphics.h>
 
 #include "Barrier.h"
 #include "DisplayDevice.h"
@@ -84,7 +86,7 @@
 class DisplayEventConnection;
 class EventThread;
 class Layer;
-class LayerDim;
+class ColorLayer;
 class Surface;
 class RenderEngine;
 class EventControlThread;
@@ -105,6 +107,7 @@
 };
 
 class SurfaceFlinger : public BnSurfaceComposer,
+                       public PriorityDumper,
                        private IBinder::DeathRecipient,
 #ifdef USE_HWC2
                        private HWC2::ComposerCallback
@@ -272,7 +275,7 @@
      */
     virtual status_t onTransact(uint32_t code, const Parcel& data,
         Parcel* reply, uint32_t flags);
-    virtual status_t dump(int fd, const Vector<String16>& args);
+    virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); }
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
@@ -410,7 +413,7 @@
             sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
             sp<Layer>* outLayer);
 
-    status_t createDimLayer(const sp<Client>& client, const String8& name,
+    status_t createColorLayer(const sp<Client>& client, const String8& name,
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
             sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
@@ -592,6 +595,13 @@
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
      */
+public:
+    status_t dumpCritical(int fd, const Vector<String16>& /*args*/) {
+        return doDump(fd, Vector<String16>());
+    }
+
+    status_t dumpAll(int fd, const Vector<String16>& args) { return doDump(fd, args); }
+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;
     void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -616,6 +626,7 @@
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
     }
+    status_t doDump(int fd, const Vector<String16>& args);
 
 #ifdef USE_HWC2
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a92e1f9..b718ec8 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -71,7 +71,7 @@
 #include "EventThread.h"
 #include "Layer.h"
 #include "LayerVector.h"
-#include "LayerDim.h"
+#include "ColorLayer.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 
@@ -179,6 +179,8 @@
     maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
 
+    mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
     char value[PROPERTY_VALUE_MAX];
 
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -2022,7 +2024,7 @@
 
                 // compute the opaque region
                 const int32_t layerOrientation = tr.getOrientation();
-                if (s.alpha==255 && !translucent &&
+                if (layer->getAlpha()==1.0f && !translucent &&
                         ((layerOrientation & Transform::ROT_INVALID) == false)) {
                     // the opaque region is the layer's footprint
                     opaqueRegion = visibleRegion;
@@ -2295,7 +2297,7 @@
                         const Layer::State& state(layer->getDrawingState());
                         if ((cur->getHints() & HWC_HINT_CLEAR_FB)
                                 && i
-                                && layer->isOpaque(state) && (state.alpha == 0xFF)
+                                && layer->isOpaque(state) && (state.color.a == 1.0f)
                                 && hasGlesComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
@@ -2620,9 +2622,14 @@
             }
         }
         if (what & layer_state_t::eAlphaChanged) {
-            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+            if (layer->setAlpha(s.alpha))
                 flags |= eTraversalNeeded;
         }
+        if (what & layer_state_t::eColorChanged) {
+            if (layer->setColor(s.color)) {
+                flags |= eTraversalNeeded;
+            }
+        }
         if (what & layer_state_t::eMatrixChanged) {
             if (layer->setMatrix(s.matrix))
                 flags |= eTraversalNeeded;
@@ -2679,6 +2686,11 @@
             // We don't trigger a traversal here because if no other state is
             // changed, we don't want this to cause any more work
         }
+        if (what & layer_state_t::eReparent) {
+            if (layer->reparent(s.parentHandleForChild)) {
+                flags |= eTransactionNeeded|eTraversalNeeded;
+            }
+        }
         if (what & layer_state_t::eReparentChildren) {
             if (layer->reparentChildren(s.reparentHandle)) {
                 flags |= eTransactionNeeded|eTraversalNeeded;
@@ -2721,8 +2733,8 @@
                     uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
-        case ISurfaceComposerClient::eFXSurfaceDim:
-            result = createDimLayer(client,
+        case ISurfaceComposerClient::eFXSurfaceColor:
+            result = createColorLayer(client,
                     uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
@@ -2797,11 +2809,11 @@
     return err;
 }
 
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
 {
-    *outLayer = new LayerDim(this, client, name, w, h, flags);
+    *outLayer = new ColorLayer(this, client, name, w, h, flags);
     *handle = (*outLayer)->getHandle();
     *gbp = (*outLayer)->getProducer();
     return NO_ERROR;
@@ -2993,7 +3005,7 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args)
 {
     String8 result;
 
@@ -4082,10 +4094,10 @@
             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=%x",
+                    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, state.alpha);
+                            layer->isVisible(), state.flags, static_cast<float>(state.color.a));
                     i++;
                 });
             }
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index db489b2..eeb4929 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -98,7 +98,7 @@
     addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
             layer->mCurrentState.active.transform.ty());
     addDepthLocked(transaction, layerId, layer->mCurrentState.z);
-    addAlphaLocked(transaction, layerId, layer->mCurrentState.alpha);
+    addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
     addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
     addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
     addCropLocked(transaction, layerId, layer->mCurrentState.crop);
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index e50f3ce..6a24891 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -105,7 +105,8 @@
 
     // publish surface flinger
     sp<IServiceManager> sm(defaultServiceManager());
-    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
+    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
+                   IServiceManager::DUMP_PRIORITY_CRITICAL);
 
     // publish GpuService
     sp<GpuService> gpuservice = new GpuService();
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6be708a..5c188dc 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*"
+            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:LayerColorTest.*"
         }
 }
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 0cc763c..ed806b8 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -22,10 +22,11 @@
 #include <android/native_window.h>
 
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
+
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 #include <ui/DisplayInfo.h>
 
 #include <fstream>
@@ -34,6 +35,8 @@
 
 namespace android {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 constexpr int32_t SCALING_UPDATE = 1;
 constexpr uint32_t BUFFER_UPDATES = 18;
 constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
@@ -149,11 +152,11 @@
         ASSERT_TRUE(mBGSurfaceControl->isValid());
         mBGLayerId = getSurfaceId("BG Interceptor Test Surface");
 
-        SurfaceComposerClient::openGlobalTransaction();
-        mComposerClient->setDisplayLayerStack(display, 0);
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-3));
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
-        SurfaceComposerClient::closeGlobalTransaction(true);
+        Transaction t;
+        t.setDisplayLayerStack(display, 0);
+        ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
+                .show(mBGSurfaceControl)
+                .apply());
     }
 
     virtual void TearDown() {
@@ -169,13 +172,14 @@
     int32_t mTargetId;
 
 public:
-    void captureTest(void (SurfaceInterceptorTest::* action)(void),
+    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
             bool (SurfaceInterceptorTest::* verification)(Trace *));
-    void captureTest(void (SurfaceInterceptorTest::* action)(void),
+    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
             SurfaceChange::SurfaceChangeCase changeCase);
-    void captureTest(void (SurfaceInterceptorTest::* action)(void),
+    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
             Increment::IncrementCase incrementCase);
-    void runInTransaction(void (SurfaceInterceptorTest::* action)(void), bool intercepted = false);
+    void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
+            bool intercepted = false);
 
     // Verification of changes to a surface
     bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
@@ -206,28 +210,29 @@
     bool bufferUpdatesFound(Trace* trace);
 
     // Perform each of the possible changes to a surface
-    void positionUpdate();
-    void sizeUpdate();
-    void alphaUpdate();
-    void layerUpdate();
-    void cropUpdate();
-    void finalCropUpdate();
-    void matrixUpdate();
-    void overrideScalingModeUpdate();
-    void transparentRegionHintUpdate();
-    void layerStackUpdate();
-    void hiddenFlagUpdate();
-    void opaqueFlagUpdate();
-    void secureFlagUpdate();
-    void deferredTransactionUpdate();
-    void runAllUpdates();
-    void surfaceCreation();
+    void positionUpdate(Transaction&);
+    void sizeUpdate(Transaction&);
+    void alphaUpdate(Transaction&);
+    void layerUpdate(Transaction&);
+    void cropUpdate(Transaction&);
+    void finalCropUpdate(Transaction&);
+    void matrixUpdate(Transaction&);
+    void overrideScalingModeUpdate(Transaction&);
+    void transparentRegionHintUpdate(Transaction&);
+    void layerStackUpdate(Transaction&);
+    void hiddenFlagUpdate(Transaction&);
+    void opaqueFlagUpdate(Transaction&);
+    void secureFlagUpdate(Transaction&);
+    void deferredTransactionUpdate(Transaction&);
+    void surfaceCreation(Transaction&);
+    void displayCreation(Transaction&);
+    void displayDeletion(Transaction&);
+
     void nBufferUpdates();
-    void displayCreation();
-    void displayDeletion();
+    void runAllUpdates();
 };
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
         bool (SurfaceInterceptorTest::* verification)(Trace *))
 {
     runInTransaction(action, true);
@@ -236,7 +241,7 @@
     ASSERT_TRUE((this->*verification)(&capturedTrace));
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
         Increment::IncrementCase incrementCase)
 {
     runInTransaction(action, true);
@@ -245,7 +250,7 @@
     ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase));
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
         SurfaceChange::SurfaceChangeCase changeCase)
 {
     runInTransaction(action, true);
@@ -254,83 +259,84 @@
     ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
 }
 
-void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(void),
+void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
         bool intercepted)
 {
     if (intercepted) {
         enableInterceptor();
     }
-    SurfaceComposerClient::openGlobalTransaction();
-    (this->*action)();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    Transaction t;
+    (this->*action)(t);
+    t.apply(true);
+
     if (intercepted) {
         disableInterceptor();
     }
 }
 
-void SurfaceInterceptorTest::positionUpdate() {
-    mBGSurfaceControl->setPosition(POSITION_UPDATE, POSITION_UPDATE);
+void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
+    t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE);
 }
 
-void SurfaceInterceptorTest::sizeUpdate() {
-    mBGSurfaceControl->setSize(SIZE_UPDATE, SIZE_UPDATE);
+void SurfaceInterceptorTest::sizeUpdate(Transaction& t) {
+    t.setSize(mBGSurfaceControl, SIZE_UPDATE, SIZE_UPDATE);
 }
 
-void SurfaceInterceptorTest::alphaUpdate() {
-    mBGSurfaceControl->setAlpha(ALPHA_UPDATE);
+void SurfaceInterceptorTest::alphaUpdate(Transaction& t) {
+    t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE);
 }
 
-void SurfaceInterceptorTest::layerUpdate() {
-    mBGSurfaceControl->setLayer(LAYER_UPDATE);
+void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
+    t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
 }
 
-void SurfaceInterceptorTest::cropUpdate() {
-    mBGSurfaceControl->setCrop(CROP_UPDATE);
+void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
+    t.setCrop(mBGSurfaceControl, CROP_UPDATE);
 }
 
-void SurfaceInterceptorTest::finalCropUpdate() {
-    mBGSurfaceControl->setFinalCrop(CROP_UPDATE);
+void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) {
+    t.setFinalCrop(mBGSurfaceControl, CROP_UPDATE);
 }
 
-void SurfaceInterceptorTest::matrixUpdate() {
-    mBGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
+void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
+    t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
 }
 
-void SurfaceInterceptorTest::overrideScalingModeUpdate() {
-    mBGSurfaceControl->setOverrideScalingMode(SCALING_UPDATE);
+void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) {
+    t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE);
 }
 
-void SurfaceInterceptorTest::transparentRegionHintUpdate() {
+void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) {
     Region region(CROP_UPDATE);
-    mBGSurfaceControl->setTransparentRegionHint(region);
+    t.setTransparentRegionHint(mBGSurfaceControl, region);
 }
 
-void SurfaceInterceptorTest::layerStackUpdate() {
-    mBGSurfaceControl->setLayerStack(STACK_UPDATE);
+void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) {
+    t.setLayerStack(mBGSurfaceControl, STACK_UPDATE);
 }
 
-void SurfaceInterceptorTest::hiddenFlagUpdate() {
-    mBGSurfaceControl->setFlags(layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) {
+    t.setFlags(mBGSurfaceControl, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
 }
 
-void SurfaceInterceptorTest::opaqueFlagUpdate() {
-    mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+void SurfaceInterceptorTest::opaqueFlagUpdate(Transaction& t) {
+    t.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
 }
 
-void SurfaceInterceptorTest::secureFlagUpdate() {
-    mBGSurfaceControl->setFlags(layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
+void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) {
+    t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
 }
 
-void SurfaceInterceptorTest::deferredTransactionUpdate() {
-    mBGSurfaceControl->deferTransactionUntil(mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
+void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
+    t.deferTransactionUntil(mBGSurfaceControl, mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
 }
 
-void SurfaceInterceptorTest::displayCreation() {
+void SurfaceInterceptorTest::displayCreation(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
     SurfaceComposerClient::destroyDisplay(testDisplay);
 }
 
-void SurfaceInterceptorTest::displayDeletion() {
+void SurfaceInterceptorTest::displayDeletion(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
     mTargetId = getDisplayId(DISPLAY_NAME.string());
     SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -353,7 +359,7 @@
     runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
 }
 
-void SurfaceInterceptorTest::surfaceCreation() {
+void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
     mComposerClient->createSurface(String8(LAYER_NAME), SIZE_UPDATE, SIZE_UPDATE,
             PIXEL_FORMAT_RGBA_8888, 0);
 }
@@ -825,8 +831,10 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
-    captureTest(&SurfaceInterceptorTest::nBufferUpdates,
-            &SurfaceInterceptorTest::bufferUpdatesFound);
+    nBufferUpdates();
+    Trace capturedTrace;
+    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+    ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
 }
 
 // If the interceptor is enabled while buffer updates are being pushed, the interceptor should
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4ce14f8..f61a978 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -19,18 +19,24 @@
 #include <android/native_window.h>
 
 #include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 #include <utils/String8.h>
 #include <ui/DisplayInfo.h>
 
 #include <math.h>
+#include <math/vec3.h>
+
+#include <functional>
 
 namespace android {
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 // Fill an RGBA_8888 formatted surface with a single color.
 static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
         uint8_t r, uint8_t g, uint8_t b, bool unlock=true) {
@@ -65,8 +71,8 @@
         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
         sp<IBinder> display(sf->getBuiltInDisplay(
                 ISurfaceComposer::eDisplayIdMain));
-        SurfaceComposerClient::openGlobalTransaction();
-        SurfaceComposerClient::closeGlobalTransaction(true);
+        SurfaceComposerClient::Transaction().apply(true);
+
         ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
                 0, INT_MAX, false));
         *sc = new ScreenCapture(cpuConsumer);
@@ -148,23 +154,21 @@
 
         fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
 
-        SurfaceComposerClient::openGlobalTransaction();
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
 
-        mComposerClient->setDisplayLayerStack(display, 0);
+            t.setLayer(mBGSurfaceControl, INT32_MAX-2)
+                .show(mBGSurfaceControl);
 
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX-2));
-        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+            t.setLayer(mFGSurfaceControl, INT32_MAX-1)
+                .setPosition(mFGSurfaceControl, 64, 64)
+                .show(mFGSurfaceControl);
 
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX-1));
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
-
-        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT32_MAX-1));
-        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2,
-                displayHeight-2));
-        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show());
-
-        SurfaceComposerClient::closeGlobalTransaction(true);
+            t.setLayer(mSyncSurfaceControl, INT32_MAX-1)
+                .setPosition(mSyncSurfaceControl, displayWidth-2,
+                        displayHeight-2)
+                .show(mSyncSurfaceControl);
+        });
     }
 
     virtual void TearDown() {
@@ -185,6 +189,12 @@
         fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
     }
 
+    void asTransaction(const std::function<void(Transaction&)>& exec) {
+        Transaction t;
+        exec(t);
+        t.apply(true);
+    }
+
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mBGSurfaceControl;
     sp<SurfaceControl> mFGSurfaceControl;
@@ -204,9 +214,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 128, 128);
+    });
+
     {
         // This should reflect the new position, but not the new color.
         SCOPED_TRACE("after move, before redraw");
@@ -239,9 +250,9 @@
     }
 
     ALOGD("resizing");
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+    });
     ALOGD("resized");
     {
         // This should not reflect the new size or color because SurfaceFlinger
@@ -277,10 +288,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    Rect cropRect(16, 16, 32, 32);
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        Rect cropRect(16, 16, 32, 32);
+        t.setCrop(mFGSurfaceControl, cropRect);
+    });
     {
         // This should crop the foreground surface.
         SCOPED_TRACE("after crop");
@@ -302,10 +313,10 @@
         sc->expectFGColor(75, 75);
         sc->expectBGColor(145, 145);
     }
-    SurfaceComposerClient::openGlobalTransaction();
-    Rect cropRect(16, 16, 32, 32);
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        Rect cropRect(16, 16, 32, 32);
+        t.setFinalCrop(mFGSurfaceControl, cropRect);
+    });
     {
         // This should crop the foreground surface.
         SCOPED_TRACE("after crop");
@@ -328,9 +339,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setLayer(mFGSurfaceControl, INT_MAX - 3);
+    });
+
     {
         // This should hide the foreground surface beneath the background.
         SCOPED_TRACE("after setLayer");
@@ -351,9 +363,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.hide(mFGSurfaceControl);
+    });
+
     {
         // This should hide the foreground surface.
         SCOPED_TRACE("after hide, before show");
@@ -363,9 +376,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mFGSurfaceControl);
+    });
+
     {
         // This should show the foreground surface.
         SCOPED_TRACE("after show");
@@ -386,9 +400,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mFGSurfaceControl, 0.75f);
+    });
+
     {
         // This should set foreground to be 75% opaque.
         SCOPED_TRACE("after setAlpha");
@@ -409,9 +424,9 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setLayerStack(mFGSurfaceControl, 1);
+    });
     {
         // This should hide the foreground surface since it goes to a different
         // layer stack.
@@ -433,10 +448,10 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFlags(
-            layer_state_t::eLayerHidden, layer_state_t::eLayerHidden));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+          t.setFlags(mFGSurfaceControl,
+                layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+    });
     {
         // This should hide the foreground surface
         SCOPED_TRACE("after setFlags");
@@ -458,10 +473,11 @@
         sc->expectBGColor(145, 145);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(M_SQRT1_2, M_SQRT1_2,
-            -M_SQRT1_2, M_SQRT1_2));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setMatrix(mFGSurfaceControl,
+                M_SQRT1_2, M_SQRT1_2,
+                -M_SQRT1_2, M_SQRT1_2);
+    });
     {
         SCOPED_TRACE("after setMatrix");
         ScreenCapture::captureScreen(&sc);
@@ -497,12 +513,12 @@
         waitForPostedBuffers();
     }
     void restoreInitialState() {
-        SurfaceComposerClient::openGlobalTransaction();
-        mFGSurfaceControl->setSize(64, 64);
-        mFGSurfaceControl->setPosition(64, 64);
-        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
-        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
-        SurfaceComposerClient::closeGlobalTransaction(true);
+        asTransaction([&](Transaction& t) {
+            t.setSize(mFGSurfaceControl, 64, 64);
+            t.setPosition(mFGSurfaceControl, 64, 64);
+            t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
+            t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+        });
 
         EXPECT_INITIAL_STATE("After restoring initial state");
     }
@@ -514,10 +530,10 @@
 
     // By default position can be updated even while
     // a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(32, 32);
-    mFGSurfaceControl->setPosition(100, 100);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 32, 32);
+        t.setPosition(mFGSurfaceControl, 100, 100);
+    });
 
     {
         SCOPED_TRACE("After moving surface");
@@ -531,11 +547,11 @@
 
     // Now we repeat with setGeometryAppliesWithResize
     // and verify the position DOESN'T latch.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setSize(32, 32);
-    mFGSurfaceControl->setPosition(100, 100);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setGeometryAppliesWithResize(mFGSurfaceControl);
+        t.setSize(mFGSurfaceControl, 32, 32);
+        t.setPosition(mFGSurfaceControl, 100, 100);
+    });
 
     {
         SCOPED_TRACE("While resize is pending");
@@ -580,20 +596,20 @@
 TEST_F(CropLatchingTest, CropLatching) {
     EXPECT_INITIAL_STATE("before anything");
     // Normally the crop applies immediately even while a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+    });
 
     EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
 
     restoreInitialState();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setGeometryAppliesWithResize(mFGSurfaceControl);
+        t.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+    });
 
     EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
 
@@ -605,20 +621,20 @@
 TEST_F(CropLatchingTest, FinalCropLatching) {
     EXPECT_INITIAL_STATE("before anything");
     // Normally the crop applies immediately even while a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
 
     restoreInitialState();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setGeometryAppliesWithResize(mFGSurfaceControl);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
 
@@ -632,10 +648,10 @@
 TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) {
     EXPECT_INITIAL_STATE("before anything");
     // Normally the crop applies immediately even while a resize is pending.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
 
@@ -645,11 +661,11 @@
     // initiating the resize.
     lockAndFillFGBuffer();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setGeometryAppliesWithResize(mFGSurfaceControl);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
 
@@ -669,17 +685,17 @@
     // In this scenario, we attempt to set the final crop a second time while the resize
     // is still pending, and ensure we are successful. Success meaning the second crop
     // is the one which eventually latches and not the first.
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setSize(128, 128);
-    mFGSurfaceControl->setGeometryAppliesWithResize();
-    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setSize(mFGSurfaceControl, 128, 128);
+        t.setGeometryAppliesWithResize(mFGSurfaceControl);
+        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+    });
 
     EXPECT_INITIAL_STATE("after setting crops with geometryAppliesWithResize");
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+    });
 
     EXPECT_INITIAL_STATE("after setting another crop");
 
@@ -699,17 +715,17 @@
     }
 
     // set up two deferred transactions on different frames
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75));
-    mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
-            mSyncSurfaceControl->getSurface()->getNextFrameNumber());
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mFGSurfaceControl, 0.75);
+        t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+    });
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128,128));
-    mFGSurfaceControl->deferTransactionUntil(mSyncSurfaceControl->getHandle(),
-            mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 128,128);
+        t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+    });
 
     {
         SCOPED_TRACE("before any trigger");
@@ -730,9 +746,9 @@
     }
 
     // should show up immediately since it's not deferred
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mFGSurfaceControl, 1.0);
+    });
 
     // trigger the second deferred transaction
     fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
@@ -761,12 +777,11 @@
     waitForPostedBuffers();
 
     // Now we stack the surface above the foreground surface and make sure it is visible.
-    SurfaceComposerClient::openGlobalTransaction();
-    relativeSurfaceControl->setPosition(64, 64);
-    relativeSurfaceControl->show();
-    relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1);
-    SurfaceComposerClient::closeGlobalTransaction(true);
-
+    asTransaction([&](Transaction& t) {
+        t.setPosition(relativeSurfaceControl, 64, 64);
+        t.show(relativeSurfaceControl);
+        t.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+    });
 
     {
         SCOPED_TRACE("after adding relative surface");
@@ -776,9 +791,9 @@
     }
 
     // A call to setLayer will override a call to setRelativeLayer
-    SurfaceComposerClient::openGlobalTransaction();
-    relativeSurfaceControl->setLayer(0);
-    SurfaceComposerClient::closeGlobalTransaction();
+    asTransaction([&](Transaction& t) {
+        t.setLayer(relativeSurfaceControl, 0);
+    });
 
     {
         SCOPED_TRACE("after set layer");
@@ -788,6 +803,40 @@
     }
 }
 
+TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
+    sp<ScreenCapture> sc;
+
+    sp<SurfaceControl> childNoBuffer =
+        mComposerClient->createSurface(String8("Bufferless child"),
+                10, 10, PIXEL_FORMAT_RGBA_8888,
+                0, mFGSurfaceControl.get());
+    sp<SurfaceControl> childBuffer = mComposerClient->createSurface(
+            String8("Buffered child"), 20, 20,
+            PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+    fillSurfaceRGBA8(childBuffer, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction{}
+            .show(childNoBuffer)
+            .show(childBuffer)
+            .apply(true);
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectChildColor(73, 73);
+        sc->expectFGColor(74, 74);
+    }
+
+    SurfaceComposerClient::Transaction{}
+            .setSize(childNoBuffer, 20, 20)
+            .apply(true);
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectChildColor(73, 73);
+        sc->expectChildColor(74, 74);
+    }
+}
+
 class ChildLayerTest : public LayerUpdateTest {
 protected:
     void SetUp() override {
@@ -814,11 +863,11 @@
 };
 
 TEST_F(ChildLayerTest, ChildLayerPositioning) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(10, 10);
-    mFGSurfaceControl->setPosition(64, 64);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -830,9 +879,9 @@
         mCapture->expectFGColor(84, 84);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -846,12 +895,12 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerCropping) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -862,12 +911,12 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerFinalCropping) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -878,11 +927,11 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerConstraints) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mFGSurfaceControl->setPosition(0, 0);
-    mChild->setPosition(63, 63);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setPosition(mChild, 63, 63);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -896,9 +945,9 @@
 }
 
 TEST_F(ChildLayerTest, ChildLayerScaling) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     // Find the boundary between the parent and child
     {
@@ -907,9 +956,9 @@
         mCapture->expectFGColor(10, 10);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
+    });
 
     // The boundary should be twice as far from the origin now.
     // The pixels from the last test should all be child now
@@ -928,11 +977,11 @@
     fillSurfaceRGBA8(mChild, 0, 254, 0);
     waitForPostedBuffers();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -940,9 +989,9 @@
         mCapture->checkPixel(0, 0, 0, 254, 0);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mChild, 0.5);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -950,9 +999,9 @@
         mCapture->checkPixel(0, 0, 127, 127, 0);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mFGSurfaceControl, 0.5);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -962,11 +1011,11 @@
 }
 
 TEST_F(ChildLayerTest, ReparentChildren) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(10, 10);
-    mFGSurfaceControl->setPosition(64, 64);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -977,7 +1026,11 @@
         // And 10 more pixels we should be back to the foreground surface
         mCapture->expectFGColor(84, 84);
     }
-    mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle());
+
+    asTransaction([&](Transaction& t) {
+        t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+    });
+
     {
         ScreenCapture::captureScreen(&mCapture);
         mCapture->expectFGColor(64, 64);
@@ -990,12 +1043,12 @@
     }
 }
 
-TEST_F(ChildLayerTest, DetachChildren) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(10, 10);
-    mFGSurfaceControl->setPosition(64, 64);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1007,13 +1060,59 @@
         mCapture->expectFGColor(84, 84);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->detachChildren();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.detachChildren(mFGSurfaceControl);
+    });
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->hide();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+    });
+
+    // Since the child has the same client as the parent, it will not get
+    // detached and will be hidden.
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectFGColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+    sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
+    sp<SurfaceControl> mChildNewClient = mNewComposerClient->createSurface(
+        String8("New Child Test Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+        0, mFGSurfaceControl.get());
+
+    ASSERT_TRUE(mChildNewClient != NULL);
+    ASSERT_TRUE(mChildNewClient->isValid());
+
+    fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
+
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+        t.show(mChildNewClient);
+        t.setPosition(mChildNewClient, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.detachChildren(mFGSurfaceControl);
+    });
+
+    asTransaction([&](Transaction& t) {
+        t.hide(mChildNewClient);
+    });
 
     // Nothing should have changed.
     {
@@ -1025,11 +1124,11 @@
 }
 
 TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1039,11 +1138,11 @@
         mCapture->expectFGColor(10, 10);
     }
 
-    SurfaceComposerClient::openGlobalTransaction();
-    mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-    // We cause scaling by 2.
-    mFGSurfaceControl->setSize(128, 128);
-    SurfaceComposerClient::closeGlobalTransaction();
+    asTransaction([&](Transaction& t) {
+        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // We cause scaling by 2.
+        t.setSize(mFGSurfaceControl, 128, 128);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1058,11 +1157,11 @@
 
 // Regression test for b/37673612
 TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->show();
-    mChild->setPosition(0, 0);
-    mFGSurfaceControl->setPosition(0, 0);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
 
     {
         ScreenCapture::captureScreen(&mCapture);
@@ -1071,11 +1170,11 @@
         // But it's only 10x10.
         mCapture->expectFGColor(10, 10);
     }
-
-
     // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
     // the WM specified state size.
-    mFGSurfaceControl->setSize(128, 64);
+    asTransaction([&](Transaction& t) {
+         t.setSize(mFGSurfaceControl, 128, 64);
+    });
     sp<Surface> s = mFGSurfaceControl->getSurface();
     auto anw = static_cast<ANativeWindow*>(s.get());
     native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1102,11 +1201,11 @@
                                             mFGSurfaceControl.get());
 
     // Show the child layer in a deferred transaction
-    SurfaceComposerClient::openGlobalTransaction();
-    mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(),
-                                  mFGSurfaceControl->getSurface()->getNextFrameNumber());
-    mChild->show();
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    asTransaction([&](Transaction& t) {
+        t.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
+                mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        t.show(mChild);
+    });
 
     // Render the foreground surface a few times
     //
@@ -1123,4 +1222,213 @@
     fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
 }
 
+TEST_F(ChildLayerTest, Reparent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.reparent(mChild, mBGSurfaceControl->getHandle());
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectFGColor(64, 64);
+        // In reparenting we should have exposed the entire foreground surface.
+        mCapture->expectFGColor(74, 74);
+        // And the child layer should now begin at 10, 10 (since the BG
+        // layer is at (0, 0)).
+        mCapture->expectBGColor(9, 9);
+        mCapture->expectChildColor(10, 10);
+    }
+}
+
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+    asTransaction([&](Transaction& t) {
+        t.reparent(mChild, nullptr);
+    });
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Nothing should have changed.
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectChildColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+    sp<SurfaceControl> newSurface = mComposerClient->createSurface(
+        String8("New Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(newSurface != NULL);
+    ASSERT_TRUE(newSurface->isValid());
+
+    fillSurfaceRGBA8(newSurface, 63, 195, 63);
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+        t.show(newSurface);
+        t.setPosition(newSurface, 10, 10);
+        t.setLayer(newSurface, INT32_MAX-2);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // At 10, 10 we should see the new surface
+        mCapture->checkPixel(10, 10, 63, 195, 63);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.reparent(newSurface, mFGSurfaceControl->getHandle());
+    });
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+        // mFGSurface, putting it at 74, 74.
+        mCapture->expectFGColor(64, 64);
+        mCapture->checkPixel(74, 74, 63, 195, 63);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, NestedChildren) {
+    sp<SurfaceControl> grandchild = mComposerClient->createSurface(
+        String8("Grandchild surface"),
+        10, 10, PIXEL_FORMAT_RGBA_8888,
+        0, mChild.get());
+    fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
+        // which begins at 64, 64
+        mCapture->checkPixel(64, 64, 50, 50, 50);
+    }
+}
+
+class LayerColorTest : public LayerUpdateTest {
+ protected:
+    void SetUp() override {
+        LayerUpdateTest::SetUp();
+
+        mLayerColorControl = mComposerClient->createSurface(
+            String8("Layer color surface"),
+            128, 128, PIXEL_FORMAT_RGBA_8888,
+            ISurfaceComposerClient::eFXSurfaceColor);
+
+        ASSERT_TRUE(mLayerColorControl != NULL);
+        ASSERT_TRUE(mLayerColorControl->isValid());
+
+        asTransaction([&](Transaction& t) {
+            t.setLayer(mLayerColorControl, INT32_MAX-1);
+            t.setPosition(mLayerColorControl, 140, 140);
+            t.hide(mLayerColorControl);
+            t.hide(mFGSurfaceControl);
+        });
+    }
+
+    void TearDown() override {
+        LayerUpdateTest::TearDown();
+        mLayerColorControl = 0;
+    }
+
+    sp<SurfaceControl> mLayerColorControl;
+};
+
+TEST_F(LayerColorTest, ColorLayerNoAlpha) {
+    sp<ScreenCapture> sc;
+
+    {
+        SCOPED_TRACE("before setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(145, 145);
+    }
+
+    asTransaction([&](Transaction& t) {
+        half3 color(43.0f/255.0f, 207.0f/255.0f, 131.0f/255.0f);
+        t.setColor(mLayerColorControl, color);
+        t.show(mLayerColorControl);
+    });
+
+    {
+        // There should now be a color
+        SCOPED_TRACE("after setColor");
+
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(145, 145, 43, 207, 131);
+    }
+}
+
+TEST_F(LayerColorTest, ColorLayerWithAlpha) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(145, 145);
+    }
+
+    asTransaction([&](Transaction& t) {
+        half3 color(43.0f/255.0f, 207.0f/255.0f, 131.0f/255.0f);
+        t.setColor(mLayerColorControl, color);
+        t.setAlpha(mLayerColorControl, .75f);
+        t.show(mLayerColorControl);
+    });
+
+    {
+        // There should now be a color with .75 alpha
+        SCOPED_TRACE("after setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(145, 145, 48, 171, 147);
+    }
+}
+
+TEST_F(LayerColorTest, ColorLayerWithNoColor) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(145, 145);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.show(mLayerColorControl);
+    });
+
+    {
+        // There should now be set to 0,0,0 (black) as default.
+        SCOPED_TRACE("after setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(145, 145, 0, 0, 0);
+    }
+}
+
 }
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 60916f3..d97ffa3 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -36,7 +36,6 @@
 #include <thread>
 
 constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
-constexpr Display DEFAULT_DISPLAY = static_cast<Display>(1);
 
 using namespace sftest;
 
@@ -168,7 +167,7 @@
     ALOGV("enableCallback");
     mCallbacksOn = enable;
     if (mCallbacksOn) {
-        mClient->onHotplug(DEFAULT_DISPLAY, IComposerCallback::Connection::CONNECTED);
+        mClient->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
     }
 }
 
@@ -507,7 +506,7 @@
         if (mSurfaceComposer != nullptr) {
             mSurfaceComposer->injectVSync(timestamp);
         } else {
-            mClient->onVsync(DEFAULT_DISPLAY, timestamp);
+            mClient->onVsync(PRIMARY_DISPLAY, timestamp);
         }
     }
 }
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index 294abb2..2a5a8ad 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -19,6 +19,9 @@
 #include "ComposerClient.h"
 #include "RenderState.h"
 
+// Needed for display type/ID enums
+#include <hardware/hwcomposer_defs.h>
+
 #include <utils/Condition.h>
 
 #include <chrono>
@@ -40,6 +43,13 @@
 
 namespace sftest {
 
+// NOTE: The ID's need to be exactly these. VR composer and parts of
+// the SurfaceFlinger assume the display IDs to have these values
+// despite the enum being documented as a display type.
+// TODO: Reference to actual documentation
+constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY);
+constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL);
+
 class FakeComposerClient : public ComposerBase {
 public:
     FakeComposerClient();
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
index 74dc0e5..1258a97 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -87,7 +87,7 @@
 
 /*
  * All surface state changes are supposed to happen inside a global
- * transaction. GlobalTransactionScope object at the beginning of
+ * transaction. TransactionScope object at the beginning of
  * scope automates the process. The resulting scope gives a visual cue
  * on the span of the transaction as well.
  *
@@ -96,23 +96,26 @@
  * is built to explicitly request vsyncs one at the time. A delayed
  * request must be made before closing the transaction or the test
  * thread stalls until SurfaceFlinger does an emergency vsync by
- * itself. GlobalTransactionScope encapsulates this vsync magic.
+ * itself. TransactionScope encapsulates this vsync magic.
  */
-class GlobalTransactionScope {
+class TransactionScope : public android::SurfaceComposerClient::Transaction {
 public:
-    GlobalTransactionScope(FakeComposerClient& composer) : mComposer(composer) {
-        android::SurfaceComposerClient::openGlobalTransaction();
+    TransactionScope(FakeComposerClient& composer) :
+            Transaction(),
+            mComposer(composer) {
     }
-    ~GlobalTransactionScope() {
+
+    ~TransactionScope() {
         int frameCount = mComposer.getFrameCount();
         mComposer.runVSyncAfter(1ms);
-        android::SurfaceComposerClient::closeGlobalTransaction(true);
+        LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply());
         // Make sure that exactly one frame has been rendered.
         mComposer.waitUntilFrame(frameCount + 1);
         LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
                             "Unexpected frame advance. Delta: %d",
                             mComposer.getFrameCount() - frameCount);
     }
+
     FakeComposerClient& mComposer;
 };
 
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 8902ede..7f4c58a 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -24,11 +24,11 @@
 
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerDebugInfo.h>
+#include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
 #include <private/gui/ComposerService.h>
-#include <private/gui/LayerState.h>
 
 #include <ui/DisplayInfo.h>
 
@@ -62,6 +62,8 @@
 using ::testing::SetArgPointee;
 using ::testing::_;
 
+using Transaction = SurfaceComposerClient::Transaction;
+
 ///////////////////////////////////////////////
 
 struct TestColor {
@@ -168,17 +170,15 @@
     android::hardware::ProcessState::self()->startThreadPool();
     android::ProcessState::self()->startThreadPool();
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(1, _))
+    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
             .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
                             Return(Error::NONE)));
-    // Seems to be doubled right now, once for display ID 1 and once for 0. This sounds fishy
-    // but encoding that here exactly.
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(1, 1, _, _))
-            .Times(5)
-            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
-    // TODO: Find out what code is generating the ID 0.
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(0, 1, _, _))
-            .Times(5)
+    // Primary display will be queried twice for all 5 attributes. One
+    // set of queries comes from the SurfaceFlinger proper an the
+    // other set from the VR composer.
+    // TODO: Is VR composer always present? Change to atLeast(5)?
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
+            .Times(2 * 5)
             .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
 
     startSurfaceFlinger();
@@ -207,31 +207,32 @@
 TEST_F(DisplayTest, Hotplug) {
     ALOGD("DisplayTest::Hotplug");
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(2, _))
+    EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
             .Times(2)
             .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
                                   Return(Error::NONE)));
     // The attribute queries will get done twice. This is for defaults
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, _, _))
+    EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
             .Times(2 * 3)
             .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
     // ... and then special handling for dimensions. Specifying this
     // rules later means that gmock will try them first, i.e.,
     // ordering of width/height vs. the default implementation for
     // other queries is significant.
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::WIDTH, _))
+    EXPECT_CALL(*mMockComposer,
+                getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
             .Times(2)
             .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
 
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::HEIGHT, _))
+    EXPECT_CALL(*mMockComposer,
+                getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
             .Times(2)
             .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
 
     // TODO: Width and height queries are not actually called. Display
     // info returns dimensions 0x0 in display info. Why?
 
-    mMockComposer->hotplugDisplay(static_cast<Display>(2),
-                                  IComposerCallback::Connection::CONNECTED);
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
 
     {
         sp<android::IBinder> display(
@@ -249,21 +250,19 @@
         fillSurfaceRGBA8(surfaceControl, BLUE);
 
         {
-            GlobalTransactionScope gts(*mMockComposer);
-            mComposerClient->setDisplayLayerStack(display, 0);
+            TransactionScope ts(*mMockComposer);
+            ts.setDisplayLayerStack(display, 0);
 
-            ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2));
-            ASSERT_EQ(NO_ERROR, surfaceControl->show());
+            ts.setLayer(surfaceControl, INT32_MAX - 2)
+                .show(surfaceControl);
         }
     }
 
-    mMockComposer->hotplugDisplay(static_cast<Display>(2),
-                                  IComposerCallback::Connection::DISCONNECTED);
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
 
     mMockComposer->clearFrames();
 
-    mMockComposer->hotplugDisplay(static_cast<Display>(2),
-                                  IComposerCallback::Connection::CONNECTED);
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
 
     {
         sp<android::IBinder> display(
@@ -281,15 +280,14 @@
         fillSurfaceRGBA8(surfaceControl, BLUE);
 
         {
-            GlobalTransactionScope gts(*mMockComposer);
-            mComposerClient->setDisplayLayerStack(display, 0);
+            TransactionScope ts(*mMockComposer);
+            ts.setDisplayLayerStack(display, 0);
 
-            ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(INT32_MAX - 2));
-            ASSERT_EQ(NO_ERROR, surfaceControl->show());
+            ts.setLayer(surfaceControl, INT32_MAX - 2)
+                .show(surfaceControl);
         }
     }
-    mMockComposer->hotplugDisplay(static_cast<Display>(2),
-                                  IComposerCallback::Connection::DISCONNECTED);
+    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
 }
 
 ////////////////////////////////////////////////
@@ -374,25 +372,24 @@
 
     fillSurfaceRGBA8(mFGSurfaceControl, RED);
 
-    SurfaceComposerClient::openGlobalTransaction();
+    Transaction t;
+    t.setDisplayLayerStack(display, 0);
 
-    mComposerClient->setDisplayLayerStack(display, 0);
+    t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
+    t.show(mBGSurfaceControl);
 
-    ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT32_MAX - 2));
-    ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
-
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT32_MAX - 1));
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
-    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+    t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
+    t.setPosition(mFGSurfaceControl, 64, 64);
+    t.show(mFGSurfaceControl);
 
     // Synchronous transaction will stop this thread, so we set up a
     // delayed, off-thread vsync request before closing the
     // transaction. In the test code this is usually done with
-    // GlobalTransactionScope. Leaving here in the 'vanilla' form for
+    // TransactionScope. Leaving here in the 'vanilla' form for
     // reference.
     ASSERT_EQ(0, sFakeComposer->getFrameCount());
     sFakeComposer->runVSyncAfter(1ms);
-    SurfaceComposerClient::closeGlobalTransaction(true);
+    t.apply();
     sFakeComposer->waitUntilFrame(1);
 
     // Reference data. This is what the HWC should see.
@@ -449,8 +446,8 @@
     // should be available in the latest frame stored by the fake
     // composer.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 128, 128);
         // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
         // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
         //
@@ -477,8 +474,8 @@
 TEST_F(TransactionTest, LayerResize) {
     ALOGD("TransactionTest::LayerResize");
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
     }
 
     fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
@@ -501,9 +498,9 @@
 TEST_F(TransactionTest, LayerCrop) {
     // TODO: Add scaling to confirm that crop happens in buffer space?
     {
-        GlobalTransactionScope gts(*sFakeComposer);
+        TransactionScope ts(*sFakeComposer);
         Rect cropRect(16, 16, 32, 32);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setCrop(cropRect));
+        ts.setCrop(mFGSurfaceControl, cropRect);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -516,9 +513,9 @@
 TEST_F(TransactionTest, LayerFinalCrop) {
     // TODO: Add scaling to confirm that crop happens in display space?
     {
-        GlobalTransactionScope gts(*sFakeComposer);
+        TransactionScope ts(*sFakeComposer);
         Rect cropRect(32, 32, 32 + 64, 32 + 64);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
+        ts.setFinalCrop(mFGSurfaceControl, cropRect);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -534,9 +531,9 @@
 TEST_F(TransactionTest, LayerFinalCropEmpty) {
     // TODO: Add scaling to confirm that crop happens in display space?
     {
-        GlobalTransactionScope gts(*sFakeComposer);
+        TransactionScope ts(*sFakeComposer);
         Rect cropRect(16, 16, 32, 32);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
+        ts.setFinalCrop(mFGSurfaceControl, cropRect);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -549,8 +546,8 @@
 
 TEST_F(TransactionTest, LayerSetLayer) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -564,11 +561,10 @@
 
 TEST_F(TransactionTest, LayerSetLayerOpaque) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX - 3));
-        ASSERT_EQ(NO_ERROR,
-                  mBGSurfaceControl->setFlags(layer_state_t::eLayerOpaque,
-                                              layer_state_t::eLayerOpaque));
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+        ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
+                layer_state_t::eLayerOpaque);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -581,8 +577,8 @@
 TEST_F(TransactionTest, SetLayerStack) {
     ALOGD("TransactionTest::SetLayerStack");
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayerStack(1));
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayerStack(mFGSurfaceControl, 1);
     }
 
     // Foreground layer should have disappeared.
@@ -595,8 +591,8 @@
 TEST_F(TransactionTest, LayerShowHide) {
     ALOGD("TransactionTest::LayerShowHide");
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
+        TransactionScope ts(*sFakeComposer);
+        ts.hide(mFGSurfaceControl);
     }
 
     // Foreground layer should have disappeared.
@@ -606,8 +602,8 @@
     EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mFGSurfaceControl);
     }
 
     // Foreground layer should be back
@@ -617,8 +613,8 @@
 
 TEST_F(TransactionTest, LayerSetAlpha) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75f));
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.75f);
     }
 
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
@@ -629,10 +625,9 @@
 
 TEST_F(TransactionTest, LayerSetFlags) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR,
-                  mFGSurfaceControl->setFlags(layer_state_t::eLayerHidden,
-                                              layer_state_t::eLayerHidden));
+        TransactionScope ts(*sFakeComposer);
+        ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
+                layer_state_t::eLayerHidden);
     }
 
     // Foreground layer should have disappeared.
@@ -664,17 +659,16 @@
              {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_H_ROT_90,    {64, 64, 128, 128}},
              {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_V_ROT_90,    {64, 64, 128, 128}}};
     // clang-format on
-    constexpr int TEST_COUNT = sizeof(MATRIX_TESTS)/sizeof(matrixTestData);
+    constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
 
     for (int i = 0; i < TEST_COUNT; i++) {
         // TODO: How to leverage the HWC2 stringifiers?
         const matrixTestData& xform = MATRIX_TESTS[i];
         SCOPED_TRACE(i);
         {
-            GlobalTransactionScope gts(*sFakeComposer);
-            ASSERT_EQ(NO_ERROR,
-                      mFGSurfaceControl->setMatrix(xform.matrix[0], xform.matrix[1],
-                                                   xform.matrix[2], xform.matrix[3]));
+            TransactionScope ts(*sFakeComposer);
+            ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1],
+                    xform.matrix[2], xform.matrix[3]);
         }
 
         auto referenceFrame = mBaseFrame;
@@ -688,10 +682,10 @@
 #if 0
 TEST_F(TransactionTest, LayerSetMatrix2) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
+        TransactionScope ts(*sFakeComposer);
         // TODO: PLEASE SPEC THE FUNCTION!
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setMatrix(0.11f, 0.123f,
-                                                         -2.33f, 0.22f));
+        ts.setMatrix(mFGSurfaceControl, 0.11f, 0.123f,
+                -2.33f, 0.22f);
     }
     auto referenceFrame = mBaseFrame;
     // TODO: Is this correct for sure?
@@ -712,10 +706,10 @@
     fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, syncSurfaceControl->setLayer(INT32_MAX - 1));
-        ASSERT_EQ(NO_ERROR, syncSurfaceControl->setPosition(mDisplayWidth - 2, mDisplayHeight - 2));
-        ASSERT_EQ(NO_ERROR, syncSurfaceControl->show());
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
+        ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
+        ts.show(syncSurfaceControl);
     }
     auto referenceFrame = mBaseFrame;
     referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
@@ -727,20 +721,20 @@
     // set up two deferred transactions on different frames - these should not yield composited
     // frames
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.75));
-        mFGSurfaceControl
-                ->deferTransactionUntil(syncSurfaceControl->getHandle(),
-                                        syncSurfaceControl->getSurface()->getNextFrameNumber());
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.75);
+        ts.deferTransactionUntil(mFGSurfaceControl, 
+                syncSurfaceControl->getHandle(),
+                syncSurfaceControl->getSurface()->getNextFrameNumber());
     }
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
-        mFGSurfaceControl
-                ->deferTransactionUntil(syncSurfaceControl->getHandle(),
-                                        syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 128, 128);
+        ts.deferTransactionUntil(mFGSurfaceControl,
+                syncSurfaceControl->getHandle(),
+                syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
     }
     EXPECT_EQ(4, sFakeComposer->getFrameCount());
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
@@ -756,8 +750,8 @@
 
     // should show up immediately since it's not deferred
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(1.0));
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 1.0);
     }
     referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
     EXPECT_EQ(6, sFakeComposer->getFrameCount());
@@ -781,10 +775,10 @@
 
     // Now we stack the surface above the foreground surface and make sure it is visible.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        relativeSurfaceControl->setPosition(64, 64);
-        relativeSurfaceControl->show();
-        relativeSurfaceControl->setRelativeLayer(mFGSurfaceControl->getHandle(), 1);
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(relativeSurfaceControl, 64, 64);
+        ts.show(relativeSurfaceControl);
+        ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
     }
     auto referenceFrame = mBaseFrame;
     // NOTE: All three layers will be visible as the surfaces are
@@ -795,8 +789,8 @@
 
     // A call to setLayer will override a call to setRelativeLayer
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        relativeSurfaceControl->setLayer(0);
+        TransactionScope ts(*sFakeComposer);
+        ts.setLayer(relativeSurfaceControl, 0);
     }
 
     // Previous top layer will now appear at the bottom.
@@ -832,11 +826,11 @@
 
 TEST_F(ChildLayerTest, Positioning) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(10, 10);
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 10, 10);
         // Move to the same position as in the original setup.
-        mFGSurfaceControl->setPosition(64, 64);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
     }
 
     auto referenceFrame = mBaseFrame;
@@ -846,8 +840,8 @@
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(0, 0));
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
     }
 
     auto referenceFrame2 = mBaseFrame;
@@ -859,11 +853,11 @@
 
 TEST_F(ChildLayerTest, Cropping) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(0, 0);
-        mFGSurfaceControl->setPosition(0, 0);
-        mFGSurfaceControl->setCrop(Rect(0, 0, 5, 5));
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
     }
     // NOTE: The foreground surface would be occluded by the child
     // now, but is included in the stack because the child is
@@ -878,11 +872,11 @@
 
 TEST_F(ChildLayerTest, FinalCropping) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(0, 0);
-        mFGSurfaceControl->setPosition(0, 0);
-        mFGSurfaceControl->setFinalCrop(Rect(0, 0, 5, 5));
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
     }
     auto referenceFrame = mBaseFrame;
     referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
@@ -894,10 +888,10 @@
 
 TEST_F(ChildLayerTest, Constraints) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mFGSurfaceControl->setPosition(0, 0);
-        mChild->setPosition(63, 63);
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setPosition(mChild, 63, 63);
     }
     auto referenceFrame = mBaseFrame;
     referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
@@ -908,8 +902,8 @@
 
 TEST_F(ChildLayerTest, Scaling) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setPosition(0, 0);
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
     }
     auto referenceFrame = mBaseFrame;
     referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
@@ -917,8 +911,8 @@
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setMatrix(2.0, 0, 0, 2.0);
+        TransactionScope ts(*sFakeComposer);
+        ts.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
     }
 
     auto referenceFrame2 = mBaseFrame;
@@ -929,11 +923,11 @@
 
 TEST_F(ChildLayerTest, LayerAlpha) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(0, 0);
-        mFGSurfaceControl->setPosition(0, 0);
-        ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setAlpha(mChild, 0.5);
     }
 
     auto referenceFrame = mBaseFrame;
@@ -943,8 +937,8 @@
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.5);
     }
 
     auto referenceFrame2 = referenceFrame;
@@ -955,10 +949,10 @@
 
 TEST_F(ChildLayerTest, ReparentChildren) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(10, 10);
-        mFGSurfaceControl->setPosition(64, 64);
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 10, 10);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
     }
     auto referenceFrame = mBaseFrame;
     referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
@@ -967,8 +961,8 @@
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle());
+        TransactionScope ts(*sFakeComposer);
+        ts.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
     }
 
     auto referenceFrame2 = referenceFrame;
@@ -979,10 +973,10 @@
 
 TEST_F(ChildLayerTest, DetachChildren) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(10, 10);
-        mFGSurfaceControl->setPosition(64, 64);
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 10, 10);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
     }
 
     auto referenceFrame = mBaseFrame;
@@ -992,13 +986,13 @@
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->detachChildren();
+        TransactionScope ts(*sFakeComposer);
+        ts.detachChildren(mFGSurfaceControl);
     }
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->hide();
+        TransactionScope ts(*sFakeComposer);
+        ts.hide(mChild);
     }
 
     // Nothing should have changed. The child control becomes a no-op
@@ -1009,17 +1003,17 @@
 
 TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(0, 0);
-        mFGSurfaceControl->setPosition(0, 0);
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
     }
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setOverrideScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        TransactionScope ts(*sFakeComposer);
+        ts.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
         // We cause scaling by 2.
-        mFGSurfaceControl->setSize(128, 128);
+        ts.setSize(mFGSurfaceControl, 128, 128);
     }
 
     auto referenceFrame = mBaseFrame;
@@ -1033,17 +1027,17 @@
 // Regression test for b/37673612
 TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->show();
-        mChild->setPosition(0, 0);
-        mFGSurfaceControl->setPosition(0, 0);
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
     }
 
     // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
     // the WM specified state size.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 64);
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 64);
     }
 
     sp<Surface> s = mFGSurfaceControl->getSurface();
@@ -1074,10 +1068,10 @@
 
     // Show the child layer in a deferred transaction
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mChild->deferTransactionUntil(mFGSurfaceControl->getHandle(),
+        TransactionScope ts(*sFakeComposer);
+        ts.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(), 
                                       mFGSurfaceControl->getSurface()->getNextFrameNumber());
-        mChild->show();
+        ts.show(mChild);
     }
 
     // Render the foreground surface a few times
@@ -1114,11 +1108,11 @@
         sFakeComposer->runVSyncAndWait();
     }
     void restoreInitialState() {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(64, 64);
-        mFGSurfaceControl->setPosition(64, 64);
-        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
-        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 64, 64);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
+        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
     }
 };
 
@@ -1126,9 +1120,9 @@
     // By default position can be updated even while
     // a resize is pending.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(32, 32);
-        mFGSurfaceControl->setPosition(100, 100);
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 32, 32);
+        ts.setPosition(mFGSurfaceControl, 100, 100);
     }
 
     // The size should not have updated as we have not provided a new buffer.
@@ -1141,10 +1135,10 @@
     // Now we repeat with setGeometryAppliesWithResize
     // and verify the position DOESN'T latch.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setGeometryAppliesWithResize();
-        mFGSurfaceControl->setSize(32, 32);
-        mFGSurfaceControl->setPosition(100, 100);
+        TransactionScope ts(*sFakeComposer);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setSize(mFGSurfaceControl, 32, 32);
+        ts.setPosition(mFGSurfaceControl, 100, 100);
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1160,9 +1154,9 @@
 TEST_F(LatchingTest, CropLatching) {
     // Normally the crop applies immediately even while a resize is pending.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
     }
 
     auto referenceFrame1 = mBaseFrame;
@@ -1173,10 +1167,10 @@
     restoreInitialState();
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setGeometryAppliesWithResize();
-        mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1192,9 +1186,9 @@
 TEST_F(LatchingTest, FinalCropLatching) {
     // Normally the crop applies immediately even while a resize is pending.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
 
     auto referenceFrame1 = mBaseFrame;
@@ -1206,10 +1200,10 @@
     restoreInitialState();
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setGeometryAppliesWithResize();
-        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1228,9 +1222,9 @@
 TEST_F(LatchingTest, FinalCropLatchingBufferOldSize) {
     // Normally the crop applies immediately even while a resize is pending.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
 
     auto referenceFrame1 = mBaseFrame;
@@ -1246,10 +1240,10 @@
     lockAndFillFGBuffer();
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setGeometryAppliesWithResize();
-        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1275,15 +1269,15 @@
     // is still pending, and ensure we are successful. Success meaning the second crop
     // is the one which eventually latches and not the first.
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setSize(128, 128);
-        mFGSurfaceControl->setGeometryAppliesWithResize();
-        mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+        TransactionScope ts(*sFakeComposer);
+        ts.setSize(mFGSurfaceControl, 128, 128);
+        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
 
     {
-        GlobalTransactionScope gts(*sFakeComposer);
-        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
+        TransactionScope ts(*sFakeComposer);
+        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk
index 203ced5..010ac9c 100644
--- a/services/surfaceflinger/tests/hwc2/Android.mk
+++ b/services/surfaceflinger/tests/hwc2/Android.mk
@@ -36,7 +36,9 @@
     libui \
     libgui \
     liblog \
-    libsync
+    libsync \
+    libhwui \
+    android.hardware.graphics.common@1.0
 LOCAL_STATIC_LIBRARIES := \
     libbase \
     libadf \
@@ -49,6 +51,7 @@
     Hwc2TestLayers.cpp \
     Hwc2TestBuffer.cpp \
     Hwc2TestClientTarget.cpp \
-    Hwc2TestVirtualDisplay.cpp
+    Hwc2TestVirtualDisplay.cpp \
+    Hwc2TestPixelComparator.cpp
 
 include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
index 4055527..4878c14 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -1775,6 +1775,145 @@
         }
     }
 
+    void createAndPresentVirtualDisplay(size_t layerCnt,
+            Hwc2TestCoverage coverage,
+            const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
+            coverageExceptions)
+    {
+        Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
+        hwc2_display_t display;
+        android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+
+        do {
+            // Items dependent on the display dimensions
+            hwc2_error_t err = HWC2_ERROR_NONE;
+            const UnsignedArea& dimension =
+                    testVirtualDisplay.getDisplayDimension();
+            ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
+                    dimension.height, &desiredFormat, &display, &err));
+            ASSERT_TRUE(err == HWC2_ERROR_NONE)
+                    << "Cannot allocate virtual display";
+
+            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+            ASSERT_NO_FATAL_FAILURE(enableVsync(display));
+
+            std::vector<hwc2_config_t> configs;
+            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+            for (auto config : configs) {
+                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+
+                Area displayArea;
+                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+                        &displayArea));
+
+                std::vector<hwc2_layer_t> layers;
+                ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers,
+                        layerCnt));
+                Hwc2TestLayers testLayers(layers, coverage, displayArea,
+                        coverageExceptions);
+
+                /*
+                 * Layouts that do not cover an entire virtual display will
+                 * cause undefined behavior.
+                 * Enable optimizeLayouts to avoid this.
+                 */
+                testLayers.optimizeLayouts();
+                do {
+                    // Items dependent on the testLayers properties
+                    std::set<hwc2_layer_t> clientLayers;
+                    std::set<hwc2_layer_t> clearLayers;
+                    uint32_t numTypes, numRequests;
+                    bool hasChanges, skip;
+                    bool flipClientTarget;
+                    int32_t presentFence;
+                    Hwc2TestClientTarget testClientTarget;
+                    buffer_handle_t outputBufferHandle;
+                    android::base::unique_fd outputBufferReleaseFence;
+
+                    ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
+                            &testLayers, &skip));
+
+                    if (skip)
+                        continue;
+
+                    ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
+                            &numRequests, &hasChanges));
+
+                    if (hasChanges)
+                        EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
+                                << "wrong number of requests";
+
+                    ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
+                            testLayers, layers, numTypes, &clientLayers));
+
+                    ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
+                            numRequests, &clearLayers, &flipClientTarget));
+                    ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
+                            &testClientTarget, testLayers, clientLayers,
+                            clearLayers, flipClientTarget, displayArea));
+                    ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
+
+                    ASSERT_EQ(testVirtualDisplay.getOutputBuffer(
+                            &outputBufferHandle, &outputBufferReleaseFence), 0);
+                    ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display,
+                            outputBufferHandle, outputBufferReleaseFence));
+
+                    EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
+                            &presentFence));
+                    ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
+
+                    ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers,
+                            &layers, &clearLayers), 0);
+
+                    /*
+                     * Upscaling the image causes minor pixel differences.
+                     * Work around this by using some threshold.
+                     *
+                     * Fail test if we are off by more than 1% of our
+                     * pixels.
+                     */
+                    ComparatorResult& comparatorResult = ComparatorResult::get();
+                    int threshold = (dimension.width * dimension.height) / 100;
+                    double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) /
+                            (dimension.width * dimension.height);
+
+                    if (comparatorResult.getDifferentPixelCount() != 0)
+                        EXPECT_TRUE(false)
+                                << comparatorResult.getDifferentPixelCount() << " pixels ("
+                                << diffPercent << "%) are different.";
+
+                    if (comparatorResult.getDifferentPixelCount() > threshold) {
+                        EXPECT_TRUE(false)
+                                << "Mismatched pixel count exceeds threshold. "
+                                << "Writing buffers to file.";
+
+                        const ::testing::TestInfo* const test_info =
+                                ::testing::UnitTest::GetInstance()
+                                ->current_test_info();
+
+                        EXPECT_EQ(testVirtualDisplay.writeBuffersToFile(
+                                test_info->name()), 0)
+                                << "Failed to write buffers.";
+                    }
+
+                    ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold)
+                            << comparatorResult.getDifferentPixelCount() << " pixels ("
+                            << diffPercent << "%) are different. "
+                            << "Exceeds 1% threshold, terminating test. "
+                            << "Test case: " << testLayers.dump();
+
+                } while (testLayers.advance());
+
+                ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
+                        std::move(layers)));
+            }
+            ASSERT_NO_FATAL_FAILURE(disableVsync(display));
+            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+            ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
+        } while (testVirtualDisplay.advance());
+    }
+
     hwc2_device_t* mHwc2Device = nullptr;
 
     enum class Hwc2TestHotplugStatus {
@@ -4479,7 +4618,7 @@
                 buffer_handle_t handle;
                 android::base::unique_fd acquireFence;
 
-                if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0)
+                if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0)
                     EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display,
                             handle, acquireFence));
             }));
@@ -4499,7 +4638,7 @@
 
                 ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
 
-                if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0)
+                if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0)
                     return;
 
                 ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay,
@@ -4539,7 +4678,7 @@
             android::base::unique_fd acquireFence;
             hwc2_error_t err = HWC2_ERROR_NONE;
 
-            if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0)
+            if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0)
                 continue;
 
             ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle,
@@ -4557,3 +4696,74 @@
 
     ASSERT_NO_FATAL_FAILURE(dump(&buffer));
 }
+
+/*
+ * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all
+ * virtual display tests as we don't handle this case correctly.
+ *
+ * Only default dataspace is supported in our drawing code.
+ */
+const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>
+        virtualDisplayExceptions =
+        {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default},
+        {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}};
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 1;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
+    const size_t layerCnt = 1;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 2;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 3;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 4;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a
+ * virtual display. */
+TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5)
+{
+    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+    const size_t layerCnt = 5;
+    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
+            virtualDisplayExceptions));
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index 1d3a1d3..6484562 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -23,14 +23,17 @@
 #include <gui/BufferItemConsumer.h>
 
 #include <ui/GraphicBuffer.h>
+#include <android/hardware/graphics/common/1.0/types.h>
 #include <math/vec4.h>
 
 #include <GLES3/gl3.h>
-
+#include <SkImageEncoder.h>
+#include <SkStream.h>
 #include "Hwc2TestBuffer.h"
 #include "Hwc2TestLayers.h"
 
 using namespace android;
+using android::hardware::graphics::common::V1_0::BufferUsage;
 
 /* Returns a fence from egl */
 typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
@@ -396,8 +399,9 @@
 {
     /* Create new graphic buffer with correct dimensions */
     mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
-            mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
-            "hwc2_test_buffer");
+            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+            BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
     int ret = mGraphicBuffer->initCheck();
     if (ret) {
         return ret;
@@ -408,7 +412,8 @@
 
     /* Locks the buffer for writing */
     uint8_t* img;
-    mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+            (void**)(&img));
 
     uint32_t stride = mGraphicBuffer->getStride();
 
@@ -458,31 +463,22 @@
 
 Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
 
-/* Generates a client target buffer using the layers assigned for client
- * composition. Takes into account the individual layer properties such as
+/* Generates a buffer from layersToDraw.
+ * Takes into account the individual layer properties such as
  * transform, blend mode, source crop, etc. */
-int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
-        int32_t* outFence, const Area& bufferArea,
+static void compositeBufferFromLayers(
+        const android::sp<android::GraphicBuffer>& graphicBuffer,
+        android_pixel_format_t format, const Area& bufferArea,
         const Hwc2TestLayers* testLayers,
-        const std::set<hwc2_layer_t>* clientLayers,
+        const std::set<hwc2_layer_t>* layersToDraw,
         const std::set<hwc2_layer_t>* clearLayers)
 {
-    /* Create new graphic buffer with correct dimensions */
-    mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
-            mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
-            "hwc2_test_buffer");
-    int ret = mGraphicBuffer->initCheck();
-    if (ret) {
-        return ret;
-    }
-    if (!mGraphicBuffer->handle) {
-        return -EINVAL;
-    }
-
+    /* Locks the buffer for writing */
     uint8_t* img;
-    mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+            (void**)(&img));
 
-    uint32_t stride = mGraphicBuffer->getStride();
+    uint32_t stride = graphicBuffer->getStride();
 
     float bWDiv3 = bufferArea.width / 3;
     float bW2Div3 = bufferArea.width * 2 / 3;
@@ -497,10 +493,10 @@
             uint8_t r = 0, g = 0, b = 0;
             float a = 0.0f;
 
-            /* Cycle through each client layer from back to front and
+            /* Cycle through each layer from back to front and
              * update the pixel color. */
-            for (auto layer = clientLayers->rbegin();
-                    layer != clientLayers->rend(); ++layer) {
+            for (auto layer = layersToDraw->rbegin();
+                    layer != layersToDraw->rend(); ++layer) {
 
                 const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
 
@@ -570,8 +566,8 @@
                      * (100x50) at the end of the transformation. */
                     if (transform & HWC_TRANSFORM_ROT_90) {
                         float tmp = xPos;
-                        xPos = -yPos * dfW / dfH;
-                        yPos = tmp * dfH / dfW;
+                        xPos = yPos * dfW / dfH;
+                        yPos = -tmp * dfH / dfW;
                     }
 
                     /* Change origin back to the top left corner of the
@@ -682,14 +678,114 @@
             }
 
             /* Set the pixel color */
-            setColor(x, y, mFormat, stride, img, r, g, b, a * 255);
+            setColor(x, y, format, stride, img, r, g, b, a * 255);
         }
     }
 
-    mGraphicBuffer->unlock();
+    graphicBuffer->unlock();
+}
+
+/* Generates a client target buffer using the layers assigned for client
+ * composition. Takes into account the individual layer properties such as
+ * transform, blend mode, source crop, etc. */
+int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
+        int32_t* outFence, const Area& bufferArea,
+        const Hwc2TestLayers* testLayers,
+        const std::set<hwc2_layer_t>* clientLayers,
+        const std::set<hwc2_layer_t>* clearLayers)
+{
+    /* Create new graphic buffer with correct dimensions */
+    mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
+            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+            BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
+    int ret = mGraphicBuffer->initCheck();
+    if (ret)
+        return ret;
+
+    if (!mGraphicBuffer->handle)
+        return -EINVAL;
+
+    compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
+            clientLayers, clearLayers);
 
     *outFence = mFenceGenerator->get();
     *outHandle = mGraphicBuffer->handle;
 
     return 0;
 }
+
+void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
+{
+    mBufferArea.width = bufferArea.width;
+    mBufferArea.height = bufferArea.height;
+}
+
+bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
+{
+    SkFILEWStream file(path.c_str());
+    const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
+            mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
+            SkAlphaType::kPremul_SkAlphaType);
+
+    uint8_t* img;
+    mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+            (void**)(&img));
+
+    SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
+    bool result = file.isValid() && SkEncodeImage(&file, pixmap,
+            SkEncodedImageFormat::kPNG, 100);
+
+    mGraphicBuffer->unlock();
+    return result;
+}
+
+/* Generates a buffer that holds the expected result of compositing all of our
+ * layers */
+int Hwc2TestExpectedBuffer::generateExpectedBuffer(
+        const Hwc2TestLayers* testLayers,
+        const std::vector<hwc2_layer_t>* allLayers,
+        const std::set<hwc2_layer_t>* clearLayers)
+{
+    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+            "hwc2_test_buffer");
+
+    int ret = mGraphicBuffer->initCheck();
+    if (ret)
+        return ret;
+
+    if (!mGraphicBuffer->handle)
+        return -EINVAL;
+
+    const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
+            allLayers->end());
+
+    compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
+            &allLayerSet, clearLayers);
+
+    return 0;
+}
+
+int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
+        int32_t* outFence)
+{
+    if (mBufferArea.width == -1 || mBufferArea.height == -1)
+        return -EINVAL;
+
+    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+            mFormat, BufferUsage::CPU_READ_OFTEN |
+            BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
+
+    int ret = mGraphicBuffer->initCheck();
+    if (ret)
+        return ret;
+
+    if (!mGraphicBuffer->handle)
+        return -EINVAL;
+
+    *outFence = -1;
+    *outHandle = mGraphicBuffer->handle;
+
+    return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
index b2b3a66..fd54fef 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
@@ -71,4 +71,38 @@
     const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 };
 
+
+class Hwc2TestVirtualBuffer {
+public:
+    void updateBufferArea(const Area& bufferArea);
+
+    bool writeBufferToFile(std::string path);
+
+    android::sp<android::GraphicBuffer>& graphicBuffer()
+    {
+        return mGraphicBuffer;
+    }
+
+protected:
+    android::sp<android::GraphicBuffer> mGraphicBuffer;
+
+    Area mBufferArea = {-1, -1};
+
+    const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+};
+
+
+class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer {
+public:
+    int generateExpectedBuffer(const Hwc2TestLayers* testLayers,
+            const std::vector<hwc2_layer_t>* allLayers,
+            const std::set<hwc2_layer_t>* clearLayers);
+};
+
+
+class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer {
+public:
+    int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence);
+};
+
 #endif /* ifndef _HWC2_TEST_BUFFER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
new file mode 100644
index 0000000..904b927
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <android/hardware/graphics/common/1.0/types.h>
+
+#include "Hwc2TestPixelComparator.h"
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
+uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride,
+        uint8_t* img) const
+{
+    uint32_t r = img[(y * stride + x) * 4 + 0];
+    uint32_t g = img[(y * stride + x) * 4 + 1];
+    uint32_t b = img[(y * stride + x) * 4 + 2];
+    uint32_t a = img[(y * stride + x) * 4 + 3];
+
+    uint32_t pixel = 0;
+    pixel |= r;
+    pixel |= g << 8;
+    pixel |= b << 16;
+    pixel |= a << 24;
+    return pixel;
+}
+
+void ComparatorResult::CompareBuffers(
+        android::sp<android::GraphicBuffer>& resultBuffer,
+        android::sp<android::GraphicBuffer>& expectedBuffer)
+{
+    uint8_t* resultBufferImg;
+    uint8_t* expectedBufferImg;
+    resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
+            (void**)(&resultBufferImg));
+
+    expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
+            (void**)(&expectedBufferImg));
+    mComparisons.clear();
+    int32_t mDifferentPixelCount = 0;
+    int32_t mBlankPixelCount = 0;
+
+    for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) {
+        for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) {
+            uint32_t result = getPixel(x, y, resultBuffer->getStride(),
+                    resultBufferImg);
+            uint32_t expected = getPixel(x, y, expectedBuffer->getStride(),
+                    expectedBufferImg);
+
+            if (result == 0)
+                mBlankPixelCount++;
+
+            if (result != expected)
+                mDifferentPixelCount++;
+
+            mComparisons.emplace_back(std::make_tuple(x, y, result, expected));
+        }
+    }
+    resultBuffer->unlock();
+    expectedBuffer->unlock();
+}
+
+std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y,
+        uint32_t resultPixel, uint32_t expectedPixel) const
+{
+    uint32_t resultAlpha = (resultPixel >> 24) & 0xFF;
+    uint32_t resultBlue = (resultPixel >> 16) & 0xFF;
+    uint32_t resultGreen = (resultPixel >> 8) & 0xFF;
+    uint32_t resultRed = resultPixel & 0xFF;
+
+    uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF;
+    uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF;
+    uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF;
+    uint32_t expectedRed = expectedPixel & 0xFF;
+
+    std::ostringstream stream;
+
+    stream << "x: " << x << " y: " << y << std::endl;
+    stream << std::hex;
+    stream << "Result pixel:   " << resultRed << "|" << resultGreen << "|"
+           << resultBlue << "|" << resultAlpha << std::endl;
+
+    stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|"
+           << expectedBlue << "|" << expectedAlpha << std::endl;
+
+    return stream.str();
+}
+
+std::string ComparatorResult::dumpComparison() const
+{
+    std::ostringstream stream;
+    stream << "Number of different pixels: " << mDifferentPixelCount;
+
+    for (const auto& comparison : mComparisons) {
+        if (std::get<2>(comparison) != std::get<3>(comparison))
+            stream << pixelDiff(std::get<0>(comparison),
+                    std::get<1>(comparison), std::get<2>(comparison),
+                    std::get<3>(comparison));
+    }
+    return stream.str();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
new file mode 100644
index 0000000..55fa936
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _HWC2_TEST_PIXEL_COMPARATOR_H
+#define _HWC2_TEST_PIXEL_COMPARATOR_H
+
+#include <ui/GraphicBuffer.h>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+class ComparatorResult {
+public:
+    static ComparatorResult& get()
+    {
+        static ComparatorResult instance;
+        return instance;
+    }
+
+    void CompareBuffers(android::sp<android::GraphicBuffer>& resultBuffer,
+            android::sp<android::GraphicBuffer>& expectedBuffer);
+
+    std::string dumpComparison() const;
+
+    ComparatorResult(const ComparatorResult&) = delete;
+    ComparatorResult(ComparatorResult&&) = delete;
+    ComparatorResult& operator=(ComparatorResult const&) = delete;
+    ComparatorResult& operator=(ComparatorResult&&) = delete;
+
+    int32_t getDifferentPixelCount() const { return mDifferentPixelCount; }
+    int32_t getBlankPixelCount() const { return mBlankPixelCount; }
+
+private:
+    ComparatorResult() = default;
+    uint32_t getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const;
+    std::string pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel,
+            uint32_t expectedPixel) const;
+
+    int32_t mDifferentPixelCount;
+    int32_t mBlankPixelCount;
+    /* std::tuple<X coordinate, Y coordinate, resultPixel, expectedPixel> */
+    std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>
+            mComparisons;
+};
+
+#endif /* ifndef _HWC2_TEST_PIXEL_COMPARATOR_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
index b5522de..5b3bbeb 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -335,9 +335,9 @@
     return dmp.str();
 }
 
-void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer)
+void Hwc2TestDisplayDimension::setDependent(Hwc2TestVirtualBuffer* buffer)
 {
-    mBuffer = buffer;
+    mBuffers.insert(buffer);
     updateDependents();
 }
 
@@ -345,8 +345,8 @@
 {
     const UnsignedArea& curr = get();
 
-    if (mBuffer)
-        mBuffer->updateBufferArea({static_cast<int32_t>(curr.width),
+    for (Hwc2TestVirtualBuffer* buffer : mBuffers)
+        buffer->updateBufferArea({static_cast<int32_t>(curr.width),
                 static_cast<int32_t>(curr.height)});
 }
 
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
index c2029ab..cb811e0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -243,6 +243,7 @@
     static const std::array<bool, 6> mCompositionSupport;
 };
 
+class Hwc2TestVirtualBuffer;
 
 class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
 public:
@@ -250,12 +251,12 @@
 
     std::string dump() const;
 
-    void setDependent(Hwc2TestBuffer* buffer);
+    void setDependent(Hwc2TestVirtualBuffer* buffer);
 
 private:
     void updateDependents();
 
-    Hwc2TestBuffer* mBuffer;
+    std::set<Hwc2TestVirtualBuffer*> mBuffers;
 
     static const std::vector<UnsignedArea> mDefaultDisplayDimensions;
     static const std::vector<UnsignedArea> mBasicDisplayDimensions;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
index d0fbc0b..e6cceb8 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
@@ -15,14 +15,18 @@
  */
 
 #include <sstream>
+#include <sys/stat.h>
 
 #include "Hwc2TestVirtualDisplay.h"
 
+#define DIR_NAME "images"
+
 Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay(
         Hwc2TestCoverage coverage)
     : mDisplayDimension(coverage)
 {
-    mDisplayDimension.setDependent(&mBuffer);
+    mDisplayDimension.setDependent(&mOutputBuffer);
+    mDisplayDimension.setDependent(&mExpectedBuffer);
 }
 
 std::string Hwc2TestVirtualDisplay::dump() const
@@ -36,11 +40,11 @@
     return dmp.str();
 }
 
-int Hwc2TestVirtualDisplay::getBuffer(buffer_handle_t* outHandle,
+int Hwc2TestVirtualDisplay::getOutputBuffer(buffer_handle_t* outHandle,
         android::base::unique_fd* outAcquireFence)
 {
     int32_t acquireFence;
-    int ret = mBuffer.get(outHandle, &acquireFence);
+    int ret = mOutputBuffer.getOutputBuffer(outHandle, &acquireFence);
     outAcquireFence->reset(acquireFence);
     return ret;
 }
@@ -59,3 +63,36 @@
 {
     return mDisplayDimension.get();
 }
+
+int Hwc2TestVirtualDisplay::verifyOutputBuffer(const Hwc2TestLayers* testLayers,
+        const std::vector<hwc2_layer_t>* allLayers,
+        const std::set<hwc2_layer_t>* clearLayers)
+{
+    int ret = mExpectedBuffer.generateExpectedBuffer(testLayers, allLayers,
+            clearLayers);
+    if (ret)
+        return ret;
+
+    ComparatorResult::get().CompareBuffers(mOutputBuffer.graphicBuffer(),
+        mExpectedBuffer.graphicBuffer());
+
+    return 0;
+}
+
+int Hwc2TestVirtualDisplay::writeBuffersToFile(std::string name)
+{
+    std::ostringstream expectedPath;
+    std::ostringstream resultPath;
+    int ret = mkdir(DIR_NAME, DEFFILEMODE);
+    if (ret && errno != EEXIST)
+        return ret;
+
+    expectedPath << DIR_NAME << "/expected-" << name << ".png";
+    resultPath << DIR_NAME << "/result-" << name << ".png";
+
+    if (!mExpectedBuffer.writeBufferToFile(expectedPath.str()) ||
+            !mOutputBuffer.writeBufferToFile(resultPath.str()))
+        return -1;
+
+    return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
index 09420ef..10c8ef0 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
@@ -18,6 +18,7 @@
 #define _HWC2_TEST_VIRTUAL_DISPLAY_H
 
 #include "Hwc2TestBuffer.h"
+#include "Hwc2TestPixelComparator.h"
 #include "Hwc2TestProperties.h"
 
 #define HWC2_INCLUDE_STRINGIFICATION
@@ -32,17 +33,22 @@
 
     std::string dump() const;
 
-    int getBuffer(buffer_handle_t* outHandle,
+    int getOutputBuffer(buffer_handle_t* outHandle,
             android::base::unique_fd* outAcquireFence);
 
+    int verifyOutputBuffer(const Hwc2TestLayers* testLayers,
+            const std::vector<hwc2_layer_t>* allLayers,
+            const std::set<hwc2_layer_t>* clearLayers);
+
+    int writeBuffersToFile(std::string name);
     void reset();
     bool advance();
 
     UnsignedArea getDisplayDimension() const;
 
 private:
-    Hwc2TestBuffer mBuffer;
-
+    Hwc2TestOutputBuffer mOutputBuffer;
+    Hwc2TestExpectedBuffer mExpectedBuffer;
     Hwc2TestDisplayDimension mDisplayDimension;
 };
 
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
index b9836ce..94c2c78 100644
--- a/services/thermalservice/thermalservice.rc
+++ b/services/thermalservice/thermalservice.rc
@@ -1,2 +1,4 @@
 service thermalservice /system/bin/thermalserviced
     class core
+    user system
+    group system
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
new file mode 100644
index 0000000..6132956
--- /dev/null
+++ b/services/utils/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+// Static library used in testing and executables
+//
+cc_library_static {
+    name: "libserviceutils",
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: [
+        "PriorityDumper.cpp",
+    ],
+
+    clang: true,
+    export_include_dirs: ["include"],
+}
+
+subdirs = ["tests"]
diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp
new file mode 100644
index 0000000..9851188
--- /dev/null
+++ b/services/utils/PriorityDumper.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/serviceutils/PriorityDumper.h"
+
+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);
+    }
+}
+
+status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args) {
+    status_t status;
+    status = dumpCritical(fd, args);
+    if (status != OK) return status;
+    status = dumpHigh(fd, args);
+    if (status != OK) return status;
+    status = dumpNormal(fd, args);
+    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);
+        } else {
+            status = dumpAll(fd, args);
+        }
+    } else {
+        status = dumpAll(fd, args);
+    }
+    return status;
+}
+} // namespace android
diff --git a/services/utils/include/serviceutils/PriorityDumper.h b/services/utils/include/serviceutils/PriorityDumper.h
new file mode 100644
index 0000000..0319242
--- /dev/null
+++ b/services/utils/include/serviceutils/PriorityDumper.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTILS_PRIORITYDUMPER_H
+#define ANDROID_UTILS_PRIORITYDUMPER_H
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+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.
+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.
+    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; }
+
+    // Dumps HIGH priority sections.
+    virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+
+    // Dumps normal priority sections.
+    virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/) { 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 ~PriorityDumper() = default;
+};
+
+} // namespace android
+
+#endif // ANDROID_UTILS_PRIORITYDUMPER_H
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
new file mode 100644
index 0000000..15829fa
--- /dev/null
+++ b/services/utils/tests/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Build unit tests.
+
+cc_test {
+    name: "prioritydumper_test",
+    test_suites: ["device-tests"],
+    srcs: [ "PriorityDumper_test.cpp"],
+    shared_libs: [
+        "libutils",
+    ],
+    static_libs = [
+        "libgmock",
+        "libserviceutils"
+    ],
+    clang: true,
+}
\ No newline at end of file
diff --git a/services/utils/tests/AndroidTest.xml b/services/utils/tests/AndroidTest.xml
new file mode 100644
index 0000000..83c890d
--- /dev/null
+++ b/services/utils/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for prioritydumper_test">
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="cleanup" value="true" />
+    <option name="push" value="prioritydumper_test->/data/local/tmp/prioritydumper_test" />
+  </target_preparer>
+  <option name="test-suite-tag" value="apct" />
+  <test class="com.android.tradefed.testtype.GTest" >
+    <option name="native-test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="prioritydumper_test" />
+  </test>
+</configuration>
\ No newline at end of file
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
new file mode 100644
index 0000000..79e7340
--- /dev/null
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "serviceutils/PriorityDumper.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+using ::testing::ElementsAreArray;
+using ::testing::Mock;
+using ::testing::Test;
+
+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>&));
+};
+
+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>&));
+};
+
+class PriorityDumperTest : public Test {
+public:
+    PriorityDumperTest() : dumper_(), dumpAlldumper_(), fd(1) {}
+    PriorityDumperMock dumper_;
+    DumpAllMock dumpAlldumper_;
+    int fd;
+};
+
+static void addAll(Vector<String16>& av, const std::vector<std::string>& v) {
+    for (auto element : v) {
+        av.add(String16(element.c_str()));
+    }
+}
+
+TEST_F(PriorityDumperTest, noArgsPassed) {
+    Vector<String16> args;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, noPriorityArgsPassed) {
+    Vector<String16> args;
+    addAll(args, {"bunch", "of", "args"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgsOnly) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "CRITICAL"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCritical) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "CRITICAL", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHigh) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "HIGH", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs)));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpNormal) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NORMAL", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs)));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpAll) {
+    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)));
+
+    dumpAlldumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "REALLY_HIGH"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+
+    dumper_.priorityDump(fd, args);
+}
\ No newline at end of file
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index a3da651..c701d48 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -16,6 +16,7 @@
 
 #include <hardware/hwvulkan.h>
 
+#include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>