[automerger skipped] RESTRICT AUTOMERGE: Fix removal of handle from map am: 6a8f8af9d0 -s ours
am skip reason: subject contains skip directive

Change-Id: I54c7cc16837e55dcfde9659cd4e8be466324d9e7
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..6a9007c
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/thermalserviced)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/thermalservice.rc)
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "gpuservice*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/gpuservice_intermediates)
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..1a932c3
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,23 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               libs/binder/ndk/
+               libs/graphicsenv/
+               libs/gui/
+               libs/renderengine/
+               libs/ui/
+               libs/vr/
+               services/bufferhub/
+               services/surfaceflinger/
+               services/vr/
+
+[Hook Scripts]
+owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
+installd_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/installd/"
+dumpstate_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/dumpstate/"
+dumpsys_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/dumpsys/"
+# bugreports matches both cmds/bugreport and cmds/bugreportz
+bugreports_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/bugreport"
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index bb84a18..cc2a6f7 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -19,6 +19,7 @@
         "libz",
         "libbase",
         "libpdx_default_transport",
+        "android.hardware.atrace@1.0",
     ],
 
     init_rc: ["atrace.rc"],
diff --git a/cmds/atrace/TEST_MAPPING b/cmds/atrace/TEST_MAPPING
new file mode 100644
index 0000000..f43db22
--- /dev/null
+++ b/cmds/atrace/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAtraceHostTestCases"
+    }
+  ]
+}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 31e73fb..a4b00f8 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -37,6 +37,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 
+#include <android/hardware/atrace/1.0/IAtraceDevice.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 
@@ -52,10 +53,16 @@
 
 using namespace android;
 using pdx::default_transport::ServiceUtility;
+using hardware::hidl_vec;
+using hardware::hidl_string;
+using hardware::Return;
+using hardware::atrace::V1_0::IAtraceDevice;
+using hardware::atrace::V1_0::Status;
+using hardware::atrace::V1_0::toString;
 
 using std::string;
 
-#define MAX_SYS_FILES 10
+#define MAX_SYS_FILES 11
 
 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
 const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -92,32 +99,31 @@
 
 /* Tracing categories */
 static const TracingCategory k_categories[] = {
-    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
-        { OPT,      "events/mdss/enable" },
-        { OPT,      "events/sde/enable" },
-    } },
-    { "input",      "Input",            ATRACE_TAG_INPUT, { } },
-    { "view",       "View System",      ATRACE_TAG_VIEW, { } },
-    { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
-    { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },
-    { "am",         "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
-    { "sm",         "Sync Manager",     ATRACE_TAG_SYNC_MANAGER, { } },
-    { "audio",      "Audio",            ATRACE_TAG_AUDIO, { } },
-    { "video",      "Video",            ATRACE_TAG_VIDEO, { } },
-    { "camera",     "Camera",           ATRACE_TAG_CAMERA, { } },
-    { "hal",        "Hardware Modules", ATRACE_TAG_HAL, { } },
-    { "res",        "Resource Loading", ATRACE_TAG_RESOURCES, { } },
-    { "dalvik",     "Dalvik VM",        ATRACE_TAG_DALVIK, { } },
-    { "rs",         "RenderScript",     ATRACE_TAG_RS, { } },
-    { "bionic",     "Bionic C Library", ATRACE_TAG_BIONIC, { } },
-    { "power",      "Power Management", ATRACE_TAG_POWER, { } },
-    { "pm",         "Package Manager",  ATRACE_TAG_PACKAGE_MANAGER, { } },
-    { "ss",         "System Server",    ATRACE_TAG_SYSTEM_SERVER, { } },
-    { "database",   "Database",         ATRACE_TAG_DATABASE, { } },
-    { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
-    { "adb",        "ADB",              ATRACE_TAG_ADB, { } },
-    { "vibrator",   "Vibrator",         ATRACE_TAG_VIBRATOR, { } },
-    { "aidl",       "AIDL calls",       ATRACE_TAG_AIDL, { } },
+    { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, { } },
+    { "input",      "Input",                    ATRACE_TAG_INPUT, { } },
+    { "view",       "View System",              ATRACE_TAG_VIEW, { } },
+    { "webview",    "WebView",                  ATRACE_TAG_WEBVIEW, { } },
+    { "wm",         "Window Manager",           ATRACE_TAG_WINDOW_MANAGER, { } },
+    { "am",         "Activity Manager",         ATRACE_TAG_ACTIVITY_MANAGER, { } },
+    { "sm",         "Sync Manager",             ATRACE_TAG_SYNC_MANAGER, { } },
+    { "audio",      "Audio",                    ATRACE_TAG_AUDIO, { } },
+    { "video",      "Video",                    ATRACE_TAG_VIDEO, { } },
+    { "camera",     "Camera",                   ATRACE_TAG_CAMERA, { } },
+    { "hal",        "Hardware Modules",         ATRACE_TAG_HAL, { } },
+    { "res",        "Resource Loading",         ATRACE_TAG_RESOURCES, { } },
+    { "dalvik",     "Dalvik VM",                ATRACE_TAG_DALVIK, { } },
+    { "rs",         "RenderScript",             ATRACE_TAG_RS, { } },
+    { "bionic",     "Bionic C Library",         ATRACE_TAG_BIONIC, { } },
+    { "power",      "Power Management",         ATRACE_TAG_POWER, { } },
+    { "pm",         "Package Manager",          ATRACE_TAG_PACKAGE_MANAGER, { } },
+    { "ss",         "System Server",            ATRACE_TAG_SYSTEM_SERVER, { } },
+    { "database",   "Database",                 ATRACE_TAG_DATABASE, { } },
+    { "network",    "Network",                  ATRACE_TAG_NETWORK, { } },
+    { "adb",        "ADB",                      ATRACE_TAG_ADB, { } },
+    { "vibrator",   "Vibrator",                 ATRACE_TAG_VIBRATOR, { } },
+    { "aidl",       "AIDL calls",               ATRACE_TAG_AIDL, { } },
+    { "nnapi",      "NNAPI",                    ATRACE_TAG_NNAPI, { } },
+    { "rro",        "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
@@ -127,7 +133,11 @@
         { OPT,      "events/sched/sched_blocked_reason/enable" },
         { OPT,      "events/sched/sched_cpu_hotplug/enable" },
         { OPT,      "events/sched/sched_pi_setprio/enable" },
+        { OPT,      "events/sched/sched_process_exit/enable" },
         { OPT,      "events/cgroup/enable" },
+        { OPT,      "events/oom/oom_score_adj_update/enable" },
+        { OPT,      "events/task/task_rename/enable" },
+        { OPT,      "events/task/task_newtask/enable" },
     } },
     { "irq",        "IRQ Events",   0, {
         { REQ,      "events/irq/enable" },
@@ -187,10 +197,12 @@
         { REQ,      "events/cpufreq_interactive/enable" },
     } },
     { "sync",       "Synchronization",  0, {
-        // before linux kernel 4.9
+        // linux kernel < 4.9
         { OPT,      "events/sync/enable" },
-        // starting in linux kernel 4.9
+        // linux kernel == 4.9.x
         { OPT,      "events/fence/enable" },
+        // linux kernel > 4.9
+        { OPT,      "events/dma_fence/enable" },
     } },
     { "workq",      "Kernel Workqueues", 0, {
         { REQ,      "events/workqueue/enable" },
@@ -208,6 +220,7 @@
     { "binder_driver", "Binder Kernel driver", 0, {
         { REQ,      "events/binder/binder_transaction/enable" },
         { REQ,      "events/binder/binder_transaction_received/enable" },
+        { REQ,      "events/binder/binder_transaction_alloc_buf/enable" },
         { OPT,      "events/binder/binder_set_priority/enable" },
     } },
     { "binder_lock", "Binder global lock trace", 0, {
@@ -218,6 +231,28 @@
     { "pagecache",  "Page cache", 0, {
         { REQ,      "events/filemap/enable" },
     } },
+    { "memory",  "Memory", 0, {
+        { OPT,      "events/kmem/rss_stat/enable" },
+        { OPT,      "events/kmem/ion_heap_grow/enable" },
+        { OPT,      "events/kmem/ion_heap_shrink/enable" },
+    } },
+};
+
+struct TracingVendorCategory {
+    // The name identifying the category.
+    std::string name;
+
+    // A longer description of the category.
+    std::string description;
+
+    // If the category is enabled through command.
+    bool enabled;
+
+    TracingVendorCategory(string &&name, string &&description, bool enabled)
+            : name(std::move(name))
+            , description(std::move(description))
+            , enabled(enabled)
+    {}
 };
 
 /* Command line options */
@@ -227,8 +262,8 @@
 static bool g_compress = false;
 static bool g_nohup = false;
 static int g_initialSleepSecs = 0;
-static const char* g_categoriesFile = NULL;
-static const char* g_kernelTraceFuncs = NULL;
+static const char* g_categoriesFile = nullptr;
+static const char* g_kernelTraceFuncs = nullptr;
 static const char* g_debugAppCmdLine = "";
 static const char* g_outputFile = nullptr;
 
@@ -237,6 +272,8 @@
 static bool g_traceAborted = false;
 static bool g_categoryEnables[arraysize(k_categories)] = {};
 static std::string g_traceFolder;
+static sp<IAtraceDevice> g_atraceHal;
+static std::vector<TracingVendorCategory> g_vendorCategories;
 
 /* Sys file paths */
 static const char* k_traceClockPath =
@@ -260,6 +297,9 @@
 static const char* k_printTgidPath =
     "options/print-tgid";
 
+static const char* k_recordTgidPath =
+    "options/record-tgid";
+
 static const char* k_funcgraphAbsTimePath =
     "options/funcgraph-abstime";
 
@@ -401,15 +441,11 @@
     for (int i = 0; i < MAX_SYS_FILES; i++) {
         const char* path = category.sysfiles[i].path;
         bool req = category.sysfiles[i].required == REQ;
-        if (path != NULL) {
-            if (req) {
-                if (!fileIsWritable(path)) {
-                    return false;
-                } else {
-                    ok = true;
-                }
-            } else {
+        if (path != nullptr) {
+            if (fileIsWritable(path)) {
                 ok = true;
+            } else if (req) {
+                return false;
             }
         }
     }
@@ -426,7 +462,7 @@
     for (int i = 0; i < MAX_SYS_FILES; i++) {
         const char* path = category.sysfiles[i].path;
         bool req = category.sysfiles[i].required == REQ;
-        if (path != NULL) {
+        if (path != nullptr) {
             if (req) {
                 if (!fileExists(path)) {
                     return false;
@@ -522,9 +558,15 @@
 
 static bool setPrintTgidEnableIfPresent(bool enable)
 {
+    // Pre-4.13 this was options/print-tgid as an android-specific option.
+    // In 4.13+ this is an upstream option called options/record-tgid
+    // Both options produce the same ftrace format change
     if (fileExists(k_printTgidPath)) {
         return setKernelOptionEnable(k_printTgidPath, enable);
     }
+    if (fileExists(k_recordTgidPath)) {
+        return setKernelOptionEnable(k_recordTgidPath, enable);
+    }
     return true;
 }
 
@@ -536,10 +578,10 @@
     Vector<String16> services = sm->listServices();
     for (size_t i = 0; i < services.size(); i++) {
         sp<IBinder> obj = sm->checkService(services[i]);
-        if (obj != NULL) {
+        if (obj != nullptr) {
             Parcel data;
             if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
-                    NULL, 0) != OK) {
+                    nullptr, 0) != OK) {
                 if (false) {
                     // XXX: For some reason this fails on tablets trying to
                     // poke the "phone" service.  It's not clear whether some
@@ -629,9 +671,9 @@
 {
     int i = 0;
     char* start = cmdline;
-    while (start != NULL) {
+    while (start != nullptr) {
         char* end = strchr(start, ',');
-        if (end != NULL) {
+        if (end != nullptr) {
             *end = '\0';
             end++;
         }
@@ -661,7 +703,7 @@
         const TracingCategory &c = k_categories[i];
         for (int j = 0; j < MAX_SYS_FILES; j++) {
             const char* path = c.sysfiles[j].path;
-            if (path != NULL && fileIsWritable(path)) {
+            if (path != nullptr && fileIsWritable(path)) {
                 ok &= setKernelOptionEnable(path, false);
             }
         }
@@ -697,7 +739,7 @@
                 ok = false;
             }
         }
-        func = strtok(NULL, ",");
+        func = strtok(nullptr, ",");
     }
     free(myFuncs);
     return ok;
@@ -708,7 +750,7 @@
 {
     bool ok = true;
 
-    if (funcs == NULL || funcs[0] == '\0') {
+    if (funcs == nullptr || funcs[0] == '\0') {
         // Disable kernel function tracing.
         if (fileIsWritable(k_currentTracerPath)) {
             ok &= writeStr(k_currentTracerPath, "nop");
@@ -730,7 +772,7 @@
         char* func = strtok(myFuncs, ",");
         while (func) {
             ok &= appendStr(k_ftraceFilterPath, func);
-            func = strtok(NULL, ",");
+            func = strtok(nullptr, ",");
         }
         free(myFuncs);
 
@@ -743,13 +785,20 @@
     return ok;
 }
 
-static bool setCategoryEnable(const char* name, bool enable)
+static bool setCategoryEnable(const char* name)
 {
+    bool vendor_found = false;
+    for (auto &c : g_vendorCategories) {
+        if (strcmp(name, c.name.c_str()) == 0) {
+            c.enabled = true;
+            vendor_found = true;
+        }
+    }
     for (size_t i = 0; i < arraysize(k_categories); i++) {
         const TracingCategory& c = k_categories[i];
         if (strcmp(name, c.name) == 0) {
             if (isCategorySupported(c)) {
-                g_categoryEnables[i] = enable;
+                g_categoryEnables[i] = true;
                 return true;
             } else {
                 if (isCategorySupportedForRoot(c)) {
@@ -763,6 +812,9 @@
             }
         }
     }
+    if (vendor_found) {
+        return true;
+    }
     fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
     return false;
 }
@@ -772,7 +824,7 @@
     if (!categories_file) {
         return true;
     }
-    Tokenizer* tokenizer = NULL;
+    Tokenizer* tokenizer = nullptr;
     if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
         return false;
     }
@@ -783,7 +835,7 @@
             tokenizer->skipDelimiters(" ");
             continue;
         }
-        ok &= setCategoryEnable(token.string(), true);
+        ok &= setCategoryEnable(token.string());
     }
     delete tokenizer;
     return ok;
@@ -838,6 +890,7 @@
     setTagsProperty(0);
     clearAppProperties();
     pokeBinderServices();
+    pokeHalServices();
 
     if (g_tracePdx) {
         ServiceUtility::PokeServices();
@@ -874,7 +927,7 @@
             for (int j = 0; j < MAX_SYS_FILES; j++) {
                 const char* path = c.sysfiles[j].path;
                 bool required = c.sysfiles[j].required == REQ;
-                if (path != NULL) {
+                if (path != nullptr) {
                     if (fileIsWritable(path)) {
                         ok &= setKernelOptionEnable(path, true);
                     } else if (required) {
@@ -899,7 +952,7 @@
     setTraceOverwriteEnable(true);
     setTraceBufferSizeKB(1);
     setPrintTgidEnableIfPresent(false);
-    setKernelTraceFuncs(NULL);
+    setKernelTraceFuncs(nullptr);
     setUserInitiatedTraceProperty(false);
 }
 
@@ -1057,10 +1110,10 @@
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
     sa.sa_handler = handleSignal;
-    sigaction(SIGHUP, &sa, NULL);
-    sigaction(SIGINT, &sa, NULL);
-    sigaction(SIGQUIT, &sa, NULL);
-    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGHUP, &sa, nullptr);
+    sigaction(SIGINT, &sa, nullptr);
+    sigaction(SIGQUIT, &sa, nullptr);
+    sigaction(SIGTERM, &sa, nullptr);
 }
 
 static void listSupportedCategories()
@@ -1071,6 +1124,9 @@
             printf("  %10s - %s\n", c.name, c.longname);
         }
     }
+    for (const auto &c : g_vendorCategories) {
+        printf("  %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
+    }
 }
 
 // Print the command usage help to stderr.
@@ -1127,6 +1183,79 @@
     return true;
 }
 
+void initVendorCategories()
+{
+    g_atraceHal = IAtraceDevice::getService();
+
+    if (g_atraceHal == nullptr) {
+        // No atrace HAL
+        return;
+    }
+
+    Return<void> ret = g_atraceHal->listCategories(
+        [](const auto& list) {
+            g_vendorCategories.reserve(list.size());
+            for (const auto& category : list) {
+                g_vendorCategories.emplace_back(category.name, category.description, false);
+            }
+        });
+    if (!ret.isOk()) {
+        fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
+    }
+}
+
+static bool setUpVendorTracing()
+{
+    if (g_atraceHal == nullptr) {
+        // No atrace HAL
+        return true;
+    }
+
+    std::vector<hidl_string> categories;
+    for (const auto &c : g_vendorCategories) {
+        if (c.enabled) {
+            categories.emplace_back(c.name);
+        }
+    }
+
+    if (!categories.size()) {
+        return true;
+    }
+
+    auto ret = g_atraceHal->enableCategories(categories);
+    if (!ret.isOk()) {
+        fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
+        return false;
+    } else if (ret != Status::SUCCESS) {
+        fprintf(stderr, "calling atrace HAL failed: %s\n", toString(ret).c_str());
+        return false;
+    }
+    return true;
+}
+
+static bool cleanUpVendorTracing()
+{
+    if (g_atraceHal == nullptr) {
+        // No atrace HAL
+        return true;
+    }
+
+    if (!g_vendorCategories.size()) {
+        // No vendor categories
+        return true;
+    }
+
+    auto ret = g_atraceHal->disableAllCategories();
+    if (!ret.isOk()) {
+        fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str());
+        return false;
+    } else if (ret != Status::SUCCESS) {
+        fprintf(stderr, "calling atrace HAL failed: %s\n", toString(ret).c_str());
+        return false;
+    }
+    return true;
+}
+
 int main(int argc, char **argv)
 {
     bool async = false;
@@ -1146,17 +1275,19 @@
         exit(-1);
     }
 
+    initVendorCategories();
+
     for (;;) {
         int ret;
         int option_index = 0;
         static struct option long_options[] = {
-            {"async_start",       no_argument, 0,  0 },
-            {"async_stop",        no_argument, 0,  0 },
-            {"async_dump",        no_argument, 0,  0 },
-            {"only_userspace",    no_argument, 0,  0 },
-            {"list_categories",   no_argument, 0,  0 },
-            {"stream",            no_argument, 0,  0 },
-            {           0,                  0, 0,  0 }
+            {"async_start",       no_argument, nullptr,  0 },
+            {"async_stop",        no_argument, nullptr,  0 },
+            {"async_dump",        no_argument, nullptr,  0 },
+            {"only_userspace",    no_argument, nullptr,  0 },
+            {"list_categories",   no_argument, nullptr,  0 },
+            {"stream",            no_argument, nullptr,  0 },
+            {nullptr,                       0, nullptr,  0 }
         };
 
         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
@@ -1164,7 +1295,7 @@
 
         if (ret < 0) {
             for (int i = optind; i < argc; i++) {
-                if (!setCategoryEnable(argv[i], true)) {
+                if (!setCategoryEnable(argv[i])) {
                     fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
                     exit(1);
                 }
@@ -1267,6 +1398,7 @@
 
     if (ok && traceStart && !onlyUserspace) {
         ok &= setUpKernelTracing();
+        ok &= setUpVendorTracing();
         ok &= startTrace();
     }
 
@@ -1285,9 +1417,7 @@
         if (!onlyUserspace)
             ok = clearTrace();
 
-        if (!onlyUserspace)
-            writeClockSyncMarker();
-
+        writeClockSyncMarker();
         if (ok && !async && !traceStream) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
@@ -1337,6 +1467,7 @@
 
     // Reset the trace buffer size to 1.
     if (traceStop) {
+        cleanUpVendorTracing();
         cleanUpUserspaceTracing();
         if (!onlyUserspace)
             cleanUpKernelTracing();
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d3d0711..f1426b6 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -19,6 +19,8 @@
     chmod 0666 /sys/kernel/tracing/options/overwrite
     chmod 0666 /sys/kernel/debug/tracing/options/print-tgid
     chmod 0666 /sys/kernel/tracing/options/print-tgid
+    chmod 0666 /sys/kernel/debug/tracing/options/record-tgid
+    chmod 0666 /sys/kernel/tracing/options/record-tgid
     chmod 0666 /sys/kernel/debug/tracing/saved_cmdlines_size
     chmod 0666 /sys/kernel/tracing/saved_cmdlines_size
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
@@ -31,6 +33,10 @@
     chmod 0666 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio/enable
     chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable
     chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable
     chmod 0666 /sys/kernel/tracing/events/cgroup/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
@@ -41,6 +47,8 @@
     chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
     chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
+    chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
     chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
     chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
     chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
@@ -57,6 +65,8 @@
     chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction/enable
     chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
     chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_transaction_alloc_buf/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable
     chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
     chmod 0666 /sys/kernel/tracing/events/binder/binder_lock/enable
     chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
@@ -87,9 +97,34 @@
     chmod 0666 /sys/kernel/tracing/events/sync/enable
     chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
     chmod 0666 /sys/kernel/tracing/events/fence/enable
-
+    chmod 0666 /sys/kernel/debug/tracing/events/dma_fence/enable
+    chmod 0666 /sys/kernel/tracing/events/dma_fence/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
+    chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_generate/enable
+    chmod 0666 /sys/kernel/tracing/events/signal/signal_generate/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_deliver/enable
+    chmod 0666 /sys/kernel/tracing/events/signal/signal_deliver/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/mm_event/mm_event_record/enable
+    chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill/enable
+    chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update/enable
+    chmod 0666 /sys/kernel/tracing/events/oom/oom_score_adj_update/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/task/task_rename/enable
+    chmod 0666 /sys/kernel/tracing/events/task/task_rename/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/task/task_newtask/enable
+    chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable
 
     # disk
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_get_data_block/enable
+    chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_iget/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_iget/enable
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable
     chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable
@@ -102,6 +137,12 @@
     chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
     chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable
     chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_enter/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_enter/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/ext4/ext4_load_inode/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_load_inode/enable
     chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable
     chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
     chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable
@@ -111,11 +152,11 @@
     chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
     chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
 
-    # graphics
-    chmod 0666 /sys/kernel/tracing/events/sde/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/sde/enable
-    chmod 0666 /sys/kernel/tracing/events/mdss/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/mdss/enable
+    # filemap events for iorapd
+    chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+    chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
 
 # Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
@@ -125,6 +166,42 @@
     chmod 0666 /sys/kernel/debug/tracing/trace
     chmod 0666 /sys/kernel/tracing/trace
 
+# Read and truncate the per-CPU kernel trace.
+# Cannot use wildcards in .rc files. Update this if there is a phone with
+# more CPUs.
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu0/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu0/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu1/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu1/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu2/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu2/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu3/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu3/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu4/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu4/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu5/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu5/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu6/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu7/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu7/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu8/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu8/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu9/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu9/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu10/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu10/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu11/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu11/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu12/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu12/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu13/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu13/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu14/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu14/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
+
 on property:persist.debug.atrace.boottrace=1
     start boottrace
 
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index f4e5b98..6c86c21 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -5,12 +5,18 @@
 # Access control to these files is now entirely in selinux policy.
 
 on post-fs
+    # On userdebug allow to enable any event via the generic
+    # set_event interface:
+    # echo sched/foo > set_event == echo 1 > events/sched/foo/enable.
+    chmod 0666 /sys/kernel/tracing/set_event
+    chmod 0666 /sys/kernel/debug/tracing/set_event
+
     chmod 0666 /sys/kernel/tracing/events/workqueue/enable
     chmod 0666 /sys/kernel/debug/tracing/events/workqueue/enable
     chmod 0666 /sys/kernel/tracing/events/regulator/enable
     chmod 0666 /sys/kernel/debug/tracing/events/regulator/enable
-    chmod 0666 /sys/kernel/tracing/events/pagecache/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/pagecache/enable
+    chmod 0666 /sys/kernel/tracing/events/filemap/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/filemap/enable
 
     # irq
     chmod 0666 /sys/kernel/tracing/events/irq/enable
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/bugreport/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp
new file mode 100644
index 0000000..924a3a3
--- /dev/null
+++ b/cmds/bugreportz/Android.bp
@@ -0,0 +1,44 @@
+// bugreportz
+// ==========
+cc_binary {
+    name: "bugreportz",
+
+    srcs: [
+        "bugreportz.cpp",
+        "main.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+    ],
+}
+
+// bugreportz_test
+// ===============
+cc_test {
+    name: "bugreportz_test",
+    test_suites: ["device-tests"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    srcs: [
+        "bugreportz.cpp",
+        "bugreportz_test.cpp",
+    ],
+
+    static_libs: ["libgmock"],
+
+    shared_libs: [
+        "libbase",
+        "libutils",
+    ],
+}
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
deleted file mode 100644
index 10dda56..0000000
--- a/cmds/bugreportz/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# bugreportz
-# ==========
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-   bugreportz.cpp \
-   main.cpp \
-
-LOCAL_MODULE:= bugreportz
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-
-include $(BUILD_EXECUTABLE)
-
-# bugreportz_test
-# ===============
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := bugreportz_test
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_SRC_FILES := \
-    bugreportz.cpp \
-    bugreportz_test.cpp \
-
-LOCAL_STATIC_LIBRARIES := \
-    libgmock \
-
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libutils \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/bugreportz/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index 75855cf..ded0ed3 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -55,7 +55,7 @@
                 errno = ETIMEDOUT;
             }
             printf("FAIL:Bugreport read terminated abnormally (%s)\n", strerror(errno));
-            break;
+            return EXIT_FAILURE;
         }
 
         // Writes line by line.
@@ -71,8 +71,5 @@
     // Process final line, in case it didn't finish with newline
     write_line(line, show_progress);
 
-    if (close(s) == -1) {
-        fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
-    }
     return EXIT_SUCCESS;
 }
diff --git a/cmds/bugreportz/bugreportz.h b/cmds/bugreportz/bugreportz.h
index 304e4b3..7af289b 100644
--- a/cmds/bugreportz/bugreportz.h
+++ b/cmds/bugreportz/bugreportz.h
@@ -16,6 +16,7 @@
 #define BUGREPORTZ_H
 
 // Calls dumpstate using the given socket and output its result to stdout.
+// Ownership of the socket is not transferred.
 int bugreportz(int s, bool show_progress);
 
 #endif  // BUGREPORTZ_H
diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp
index a3ae1ff..74a95b0 100644
--- a/cmds/bugreportz/main.cpp
+++ b/cmds/bugreportz/main.cpp
@@ -82,7 +82,7 @@
 
     if (s == -1) {
         printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
-        return EXIT_SUCCESS;
+        return EXIT_FAILURE;
     }
 
     // Set a timeout so that if nothing is read in 10 minutes, we'll stop
@@ -92,8 +92,16 @@
     tv.tv_sec = 10 * 60;
     tv.tv_usec = 0;
     if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
-        fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+        fprintf(stderr,
+                "WARNING: Cannot set socket timeout, bugreportz might hang indefinitely: %s\n",
+                strerror(errno));
     }
 
-    bugreportz(s, show_progress);
+    int ret = bugreportz(s, show_progress);
+
+    if (close(s) == -1) {
+        fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
+        ret = EXIT_FAILURE;
+    }
+    return ret;
 }
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
new file mode 100644
index 0000000..8ea71cd
--- /dev/null
+++ b/cmds/cmd/Android.bp
@@ -0,0 +1,42 @@
+cc_library_static {
+    name: "libcmd",
+
+    srcs: ["cmd.cpp"],
+    export_include_dirs: ["."],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libselinux",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DXP_UNIX",
+    ],
+}
+
+cc_binary {
+    name: "cmd",
+
+    srcs: ["main.cpp"],
+
+    static_libs: [
+        "libcmd",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libselinux",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DXP_UNIX",
+    ],
+}
diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk
deleted file mode 100644
index 4868555..0000000
--- a/cmds/cmd/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	cmd.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libutils \
-	liblog \
-    libselinux \
-	libbinder
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_C_INCLUDES += \
-    $(JNI_H_INCLUDE)
-
-ifeq ($(TARGET_OS),linux)
-	LOCAL_CFLAGS += -DXP_UNIX
-	#LOCAL_SHARED_LIBRARIES += librt
-endif
-
-LOCAL_MODULE:= cmd
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 48d5d4a..7b4aeb2 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -40,6 +40,8 @@
 #include "selinux/selinux.h"
 #include "selinux/android.h"
 
+#include "cmd.h"
+
 #define DEBUG 0
 
 using namespace android;
@@ -59,8 +61,11 @@
 class MyShellCallback : public BnShellCallback
 {
 public:
+    TextOutput& mErrorLog;
     bool mActive = true;
 
+    MyShellCallback(TextOutput& errorLog) : mErrorLog(errorLog) {}
+
     virtual int openFile(const String16& path, const String16& seLinuxContext,
             const String16& mode) {
         String8 path8(path);
@@ -69,7 +74,7 @@
         String8 fullPath(cwd);
         fullPath.appendPath(path8);
         if (!mActive) {
-            aerr << "Open attempt after active for: " << fullPath << endl;
+            mErrorLog << "Open attempt after active for: " << fullPath << endl;
             return -EPERM;
         }
 #if DEBUG
@@ -78,20 +83,20 @@
         int flags = 0;
         bool checkRead = false;
         bool checkWrite = false;
-        if (mode == String16("w")) {
+        if (mode == u"w") {
             flags = O_WRONLY|O_CREAT|O_TRUNC;
             checkWrite = true;
-        } else if (mode == String16("w+")) {
+        } else if (mode == u"w+") {
             flags = O_RDWR|O_CREAT|O_TRUNC;
             checkRead = checkWrite = true;
-        } else if (mode == String16("r")) {
+        } else if (mode == u"r") {
             flags = O_RDONLY;
             checkRead = true;
-        } else if (mode == String16("r+")) {
+        } else if (mode == u"r+") {
             flags = O_RDWR;
             checkRead = checkWrite = true;
         } else {
-            aerr << "Invalid mode requested: " << mode.string() << endl;
+            mErrorLog << "Invalid mode requested: " << mode.string() << endl;
             return -EINVAL;
         }
         int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
@@ -103,34 +108,30 @@
         }
         if (is_selinux_enabled() && seLinuxContext.size() > 0) {
             String8 seLinuxContext8(seLinuxContext);
-            security_context_t tmp = NULL;
+            security_context_t tmp = nullptr;
             getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
             if (checkWrite) {
                 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                        "file", "write", NULL);
+                        "file", "write", nullptr);
                 if (accessGranted != 0) {
 #if DEBUG
                     ALOGD("openFile: failed selinux write check!");
 #endif
                     close(fd);
-                    aerr << "System server has no access to write file context " << context.get()
-                            << " (from path " << fullPath.string() << ", context "
-                            << seLinuxContext8.string() << ")" << endl;
+                    mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl;
                     return -EPERM;
                 }
             }
             if (checkRead) {
                 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                        "file", "read", NULL);
+                        "file", "read", nullptr);
                 if (accessGranted != 0) {
 #if DEBUG
                     ALOGD("openFile: failed selinux read check!");
 #endif
                     close(fd);
-                    aerr << "System server has no access to read file context " << context.get()
-                            << " (from path " << fullPath.string() << ", context "
-                            << seLinuxContext8.string() << ")" << endl;
+                    mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl;
                     return -EPERM;
                 }
             }
@@ -163,85 +164,86 @@
     }
 };
 
-int main(int argc, char* const argv[])
-{
-    signal(SIGPIPE, SIG_IGN);
+int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
+            int in, int out, int err, RunMode runMode) {
     sp<ProcessState> proc = ProcessState::self();
-    // setThreadPoolMaxThreadCount(0) actually tells the kernel it's
-    // not allowed to spawn any additional threads, but we still spawn
-    // a binder thread from userspace when we call startThreadPool().
-    // This is safe because we only have 2 callbacks, neither of which
-    // block.
-    // See b/36066697 for rationale
-    proc->setThreadPoolMaxThreadCount(0);
     proc->startThreadPool();
 
 #if DEBUG
     ALOGD("cmd: starting");
 #endif
     sp<IServiceManager> sm = defaultServiceManager();
-    fflush(stdout);
-    if (sm == NULL) {
+    if (runMode == RunMode::kStandalone) {
+        fflush(stdout);
+    }
+    if (sm == nullptr) {
         ALOGW("Unable to get default service manager!");
-        aerr << "cmd: Unable to get default service manager!" << endl;
+        errorLog << "cmd: Unable to get default service manager!" << endl;
         return 20;
     }
 
-    if (argc == 1) {
-        aerr << "cmd: No service specified; use -l to list all services" << endl;
+    int argc = argv.size();
+
+    if (argc == 0) {
+        errorLog << "cmd: No service specified; use -l to list all services" << endl;
         return 20;
     }
 
-    if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) {
+    if ((argc == 1) && (argv[0] == "-l")) {
         Vector<String16> services = sm->listServices();
         services.sort(sort_func);
-        aout << "Currently running services:" << endl;
+        outputLog << "Currently running services:" << endl;
 
         for (size_t i=0; i<services.size(); i++) {
             sp<IBinder> service = sm->checkService(services[i]);
-            if (service != NULL) {
-                aout << "  " << services[i] << endl;
+            if (service != nullptr) {
+                outputLog << "  " << services[i] << endl;
             }
         }
         return 0;
     }
 
+    const auto cmd = argv[0];
+
     Vector<String16> args;
-    for (int i=2; i<argc; i++) {
-        args.add(String16(argv[i]));
+    String16 serviceName = String16(cmd.data(), cmd.size());
+    for (int i = 1; i < argc; i++) {
+        args.add(String16(argv[i].data(), argv[i].size()));
     }
-    String16 cmd = String16(argv[1]);
-    sp<IBinder> service = sm->checkService(cmd);
-    if (service == NULL) {
-        ALOGW("Can't find service %s", argv[1]);
-        aerr << "cmd: Can't find service: " << argv[1] << endl;
+    sp<IBinder> service = sm->checkService(serviceName);
+    if (service == nullptr) {
+        if (runMode == RunMode::kStandalone) {
+            ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data());
+        }
+        errorLog << "cmd: Can't find service: " << cmd << endl;
         return 20;
     }
 
-    sp<MyShellCallback> cb = new MyShellCallback();
+    sp<MyShellCallback> cb = new MyShellCallback(errorLog);
     sp<MyResultReceiver> result = new MyResultReceiver();
 
 #if DEBUG
-    ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", argv[1], STDIN_FILENO, STDOUT_FILENO,
-            STDERR_FILENO);
+    ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", cmd, in, out, err);
 #endif
 
     // TODO: block until a result is returned to MyResultReceiver.
-    status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
-            cb, result);
-    if (err < 0) {
+    status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
+    if (error < 0) {
         const char* errstr;
-        switch (err) {
+        switch (error) {
             case BAD_TYPE: errstr = "Bad type"; break;
             case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
             case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
             case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
-            default: errstr = strerror(-err); break;
+            default: errstr = strerror(-error); break;
         }
-        ALOGW("Failure calling service %s: %s (%d)", argv[1], errstr, -err);
-        aout << "cmd: Failure calling service " << argv[1] << ": " << errstr << " ("
-                << (-err) << ")" << endl;
-        return err;
+        if (runMode == RunMode::kStandalone) {
+            ALOGW("Failure calling service %.*s: %s (%d)", static_cast<int>(cmd.size()), cmd.data(),
+                  errstr, -error);
+        }
+        outputLog << "cmd: Failure calling service " << cmd << ": " << errstr << " (" << (-error)
+                  << ")" << endl;
+        return error;
     }
 
     cb->mActive = false;
diff --git a/cmds/cmd/cmd.h b/cmds/cmd/cmd.h
new file mode 100644
index 0000000..a91e009
--- /dev/null
+++ b/cmds/cmd/cmd.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/TextOutput.h>
+
+#include <string_view>
+#include <vector>
+
+enum class RunMode {
+    kStandalone,
+    kLibrary,
+};
+
+int cmdMain(const std::vector<std::string_view>& argv, android::TextOutput& outputLog,
+            android::TextOutput& errorLog, int in, int out, int err, RunMode runMode);
diff --git a/cmds/cmd/main.cpp b/cmds/cmd/main.cpp
new file mode 100644
index 0000000..2256e2a
--- /dev/null
+++ b/cmds/cmd/main.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 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 <unistd.h>
+
+#include "cmd.h"
+
+int main(int argc, char* const argv[]) {
+    signal(SIGPIPE, SIG_IGN);
+
+    std::vector<std::string_view> arguments;
+    arguments.reserve(argc - 1);
+    // 0th argument is a program name, skipping.
+    for (int i = 1; i < argc; ++i) {
+        arguments.emplace_back(argv[i]);
+    }
+
+    return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,
+                   STDERR_FILENO, RunMode::kStandalone);
+}
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index b04543b..ee32cb4 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -57,10 +57,19 @@
         export_aidl_headers: true,
     },
     srcs: [
-        "binder/android/os/IDumpstate.aidl",
+        ":dumpstate_aidl",
+    ],
+    export_include_dirs: ["binder"],
+}
+
+filegroup {
+    name: "dumpstate_aidl",
+    srcs: [
         "binder/android/os/IDumpstateListener.aidl",
         "binder/android/os/IDumpstateToken.aidl",
+        "binder/android/os/IDumpstate.aidl",
     ],
+    path: "binder",
 }
 
 cc_defaults {
@@ -88,8 +97,9 @@
         "utils.cpp",
     ],
     static_libs: [
+        "libincidentcompanion",
         "libdumpsys",
-        "libserviceutils"
+        "libserviceutils",
     ],
 }
 
@@ -100,6 +110,31 @@
         "dumpstate.cpp",
         "main.cpp",
     ],
+    required: [
+        "atrace",
+        "df",
+        "getprop",
+        "ip",
+        "iptables",
+        "ip6tables",
+        "kill",
+        "librank",
+        "logcat",
+        "lsmod",
+        "lsof",
+        "netstat",
+        "parse_radio_log",
+        "printenv",
+        "procrank",
+        "screencap",
+        "showmap",
+        "ss",
+        "storaged",
+        "top",
+        "uptime",
+        "vdc",
+        "vril-dump",
+    ],
     init_rc: ["dumpstate.rc"],
 }
 
@@ -107,6 +142,7 @@
     name: "dumpstate_test",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "dumpstate.cpp",
         "tests/dumpstate_test.cpp",
     ],
     static_libs: ["libgmock"],
@@ -121,3 +157,22 @@
     ],
     static_libs: ["libgmock"],
 }
+
+
+// =======================#
+// dumpstate_test_fixture #
+// =======================#
+cc_test {
+
+    name: "dumpstate_test_fixture",
+    test_suites: ["device-tests"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+    srcs: ["tests/dumpstate_test_fixture.cpp"],
+    data: ["tests/testdata/**/*"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
deleted file mode 100644
index ea5fbf1..0000000
--- a/cmds/dumpstate/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# =======================#
-# dumpstate_test_fixture #
-# =======================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := dumpstate_test_fixture
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := \
-       -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES := \
-        tests/dumpstate_test_fixture.cpp
-
-LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, tests/testdata)
-
-include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 49a78e7..ddae9ea 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -18,20 +18,51 @@
 
 #include "DumpstateService.h"
 
-#include <android-base/stringprintf.h>
+#include <memory>
 
+#include <android-base/stringprintf.h>
 #include "android/os/BnDumpstate.h"
 
 #include "DumpstateInternal.h"
 
+using android::base::StringPrintf;
+
 namespace android {
 namespace os {
 
 namespace {
-class DumpstateToken : public BnDumpstateToken {};
+
+struct DumpstateInfo {
+  public:
+    Dumpstate* ds = nullptr;
+    int32_t calling_uid = -1;
+    std::string calling_package;
+};
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+    MYLOGE("%s (%d) ", msg.c_str(), code);
+    return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
 }
 
-DumpstateService::DumpstateService() : ds_(Dumpstate::GetInstance()) {
+// Creates a bugreport and exits, thus preserving the oneshot nature of the service.
+// Note: takes ownership of data.
+[[noreturn]] static void* dumpstate_thread_main(void* data) {
+    std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
+    ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package);
+    MYLOGD("Finished taking a bugreport. Exiting.\n");
+    exit(0);
+}
+
+[[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
+    listener->onError(error_code);
+    exit(0);
+}
+
+class DumpstateToken : public BnDumpstateToken {};
+
+}  // namespace
+
+DumpstateService::DumpstateService() : ds_(nullptr) {
 }
 
 char const* DumpstateService::getServiceName() {
@@ -50,6 +81,8 @@
     return android::OK;
 }
 
+// Note: this method is part of the old flow and is not expected to be used in combination
+// with startBugreport.
 binder::Status DumpstateService::setListener(const std::string& name,
                                              const sp<IDumpstateListener>& listener,
                                              bool getSectionDetails,
@@ -64,43 +97,129 @@
         return binder::Status::ok();
     }
     std::lock_guard<std::mutex> lock(lock_);
-    if (ds_.listener_ != nullptr) {
-        MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_.listener_name_.c_str());
+    if (ds_ == nullptr) {
+        ds_ = &(Dumpstate::GetInstance());
+    }
+    if (ds_->listener_ != nullptr) {
+        MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
         return binder::Status::ok();
     }
 
-    ds_.listener_name_ = name;
-    ds_.listener_ = listener;
-    ds_.report_section_ = getSectionDetails;
+    ds_->listener_name_ = name;
+    ds_->listener_ = listener;
+    ds_->report_section_ = getSectionDetails;
     *returned_token = new DumpstateToken();
 
     return binder::Status::ok();
 }
 
+binder::Status DumpstateService::startBugreport(int32_t calling_uid,
+                                                const std::string& calling_package,
+                                                const android::base::unique_fd& bugreport_fd,
+                                                const android::base::unique_fd& screenshot_fd,
+                                                int bugreport_mode,
+                                                const sp<IDumpstateListener>& listener) {
+    MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
+
+    // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
+    // time.
+    std::lock_guard<std::mutex> lock(lock_);
+    if (ds_ != nullptr) {
+        MYLOGE("Error! There is already a bugreport in progress. Returning.");
+        if (listener != nullptr) {
+            listener->onError(IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
+        }
+        return exception(binder::Status::EX_SERVICE_SPECIFIC,
+                         "There is already a bugreport in progress");
+    }
+
+    // From here on, all conditions that indicate we are done with this incoming request should
+    // result in exiting the service to free it up for next invocation.
+    if (listener == nullptr) {
+        MYLOGE("Invalid input: no listener");
+        exit(0);
+    }
+
+    if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WEAR &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI &&
+        bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) {
+        MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode);
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+    }
+
+    if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) {
+        // TODO(b/111441001): screenshot fd should be optional
+        MYLOGE("Invalid filedescriptor");
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+    }
+
+    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+    options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
+                        screenshot_fd);
+
+    ds_ = &(Dumpstate::GetInstance());
+    ds_->SetOptions(std::move(options));
+    ds_->listener_ = listener;
+
+    DumpstateInfo* ds_info = new DumpstateInfo();
+    ds_info->ds = ds_;
+    ds_info->calling_uid = calling_uid;
+    ds_info->calling_package = calling_package;
+
+    pthread_t thread;
+    status_t err = pthread_create(&thread, nullptr, dumpstate_thread_main, ds_info);
+    if (err != 0) {
+        delete ds_info;
+        ds_info = nullptr;
+        MYLOGE("Could not create a thread");
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+    }
+    return binder::Status::ok();
+}
+
+binder::Status DumpstateService::cancelBugreport() {
+    // This is a no-op since the cancellation is done from java side via setting sys properties.
+    // See BugreportManagerServiceImpl.
+    // TODO(b/111441001): maybe make native and java sides use different binder interface
+    // to avoid these annoyances.
+    return binder::Status::ok();
+}
+
 status_t DumpstateService::dump(int fd, const Vector<String16>&) {
-    dprintf(fd, "id: %d\n", ds_.id_);
-    dprintf(fd, "pid: %d\n", ds_.pid_);
-    dprintf(fd, "update_progress: %s\n", ds_.update_progress_ ? "true" : "false");
-    dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
-    dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
+    if (ds_ == nullptr) {
+        dprintf(fd, "Bugreport not in progress yet");
+        return NO_ERROR;
+    }
+    std::string destination = ds_->options_->bugreport_fd.get() != -1
+                                  ? StringPrintf("[fd:%d]", ds_->options_->bugreport_fd.get())
+                                  : ds_->bugreport_internal_dir_.c_str();
+    dprintf(fd, "id: %d\n", ds_->id_);
+    dprintf(fd, "pid: %d\n", ds_->pid_);
+    dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
+    dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
+    dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
     dprintf(fd, "progress:\n");
-    ds_.progress_->Dump(fd, "  ");
-    dprintf(fd, "args: %s\n", ds_.args_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
-    dprintf(fd, "version: %s\n", ds_.version_.c_str());
-    dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
-    dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
-    dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
-    dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
-    dprintf(fd, "path: %s\n", ds_.path_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str());
-    dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
-    dprintf(fd, "name: %s\n", ds_.name_.c_str());
-    dprintf(fd, "now: %ld\n", ds_.now_);
-    dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
-    dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
-    dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str());
-    dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str());
+    ds_->progress_->Dump(fd, "  ");
+    dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
+    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+    dprintf(fd, "version: %s\n", ds_->version_.c_str());
+    dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
+    dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
+    dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
+    dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
+    dprintf(fd, "path: %s\n", ds_->path_.c_str());
+    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+    dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
+    dprintf(fd, "name: %s\n", ds_->name_.c_str());
+    dprintf(fd, "now: %ld\n", ds_->now_);
+    dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
+    dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
+    dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
+    dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
 
     return NO_ERROR;
 }
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 7bca24a..68eda47 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <vector>
 
+#include <android-base/unique_fd.h>
 #include <binder/BinderService.h>
 
 #include "android/os/BnDumpstate.h"
@@ -41,8 +42,20 @@
                                bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
+    binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
+                                  const android::base::unique_fd& bugreport_fd,
+                                  const android::base::unique_fd& screenshot_fd, int bugreport_mode,
+                                  const sp<IDumpstateListener>& listener) override;
+
+    // No-op
+    binder::Status cancelBugreport();
+
   private:
-    Dumpstate& ds_;
+    // Dumpstate object which contains all the bugreporting logic.
+    // Note that dumpstate is a oneshot service, so this object is meant to be used at most for
+    // one bugreport.
+    // This service does not own this object.
+    Dumpstate* ds_;
     std::mutex lock_;
 };
 
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 85eb464..97c8ae2 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -56,11 +56,11 @@
     timespec ts;
     ts.tv_sec = MSEC_TO_SEC(timeout_ms);
     ts.tv_nsec = (timeout_ms % 1000) * 1000000;
-    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
+    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
     int saved_errno = errno;
 
     // Set the signals back the way they were.
-    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
+    if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
         printf("*** sigprocmask failed: %s\n", strerror(errno));
         if (ret == 0) {
             return false;
@@ -101,13 +101,16 @@
 }
 
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() {
-    values.account_mode_ = SU_ROOT;
+    if (!PropertiesHelper::IsUnroot()) {
+        values.account_mode_ = SU_ROOT;
+    }
     return *this;
 }
 
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
-    if (!PropertiesHelper::IsUserBuild())
-        values.account_mode_ = SU_ROOT;
+    if (!PropertiesHelper::IsUserBuild()) {
+        return AsRoot();
+    }
     return *this;
 }
 
@@ -176,6 +179,7 @@
 
 std::string PropertiesHelper::build_type_ = "";
 int PropertiesHelper::dry_run_ = -1;
+int PropertiesHelper::unroot_ = -1;
 
 bool PropertiesHelper::IsUserBuild() {
     if (build_type_.empty()) {
@@ -191,6 +195,13 @@
     return dry_run_ == 1;
 }
 
+bool PropertiesHelper::IsUnroot() {
+    if (unroot_ == -1) {
+        unroot_ = android::base::GetBoolProperty("dumpstate.unroot", false) ? 1 : 0;
+    }
+    return unroot_ == 1;
+}
+
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
     if (fd.get() < 0) {
@@ -310,7 +321,7 @@
         struct sigaction sigact;
         memset(&sigact, 0, sizeof(sigact));
         sigact.sa_handler = SIG_IGN;
-        sigaction(SIGPIPE, &sigact, NULL);
+        sigaction(SIGPIPE, &sigact, nullptr);
 
         execvp(path, (char**)args.data());
         // execvp's result will be handled after waitpid_with_timeout() below, but
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 8342099..d75b08c 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -76,7 +76,7 @@
   private:
     class CommandOptionsValues {
       private:
-        CommandOptionsValues(int64_t timeout_ms);
+        explicit CommandOptionsValues(int64_t timeout_ms);
 
         int64_t timeout_ms_;
         bool always_;
@@ -88,7 +88,7 @@
         friend class CommandOptionsBuilder;
     };
 
-    CommandOptions(const CommandOptionsValues& values);
+    explicit CommandOptions(const CommandOptionsValues& values);
 
     const CommandOptionsValues values;
 
@@ -97,9 +97,16 @@
       public:
         /* Sets the command to always run, even on `dry-run` mode. */
         CommandOptionsBuilder& Always();
-        /* Sets the command's PrivilegeMode as `SU_ROOT` */
+        /*
+         * Sets the command's PrivilegeMode as `SU_ROOT` unless overridden by system property
+         * 'dumpstate.unroot'.
+         */
         CommandOptionsBuilder& AsRoot();
-        /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+        /*
+         * Runs AsRoot() on userdebug builds. No-op on user builds since 'su' is
+         * not available. This is used for commands that return some useful information even
+         * when run as shell.
+         */
         CommandOptionsBuilder& AsRootIfAvailable();
         /* Sets the command's PrivilegeMode as `DROP_ROOT` */
         CommandOptionsBuilder& DropRoot();
@@ -112,7 +119,7 @@
         CommandOptions Build();
 
       private:
-        CommandOptionsBuilder(int64_t timeout_ms);
+        explicit CommandOptionsBuilder(int64_t timeout_ms);
         CommandOptionsValues values;
         friend class CommandOptions;
     };
@@ -162,9 +169,17 @@
      */
     static bool IsDryRun();
 
+    /**
+     * Checks whether root availability should be overridden.
+     *
+     * Useful to verify how dumpstate would work in a device with an user build.
+     */
+    static bool IsUnroot();
+
   private:
     static std::string build_type_;
     static int dry_run_;
+    static int unroot_;
 };
 
 /*
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/dumpstate/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 0302ea5..c818c05 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -14,7 +14,8 @@
 mmm -j frameworks/native/cmds/dumpstate
 ```
 
-If you're working on device-specific code, you might need to build them as well. Example:
+If you're working on device-specific code, you might need to build them as well.
+Example:
 
 ```
 mmm -j frameworks/native/cmds/dumpstate device/acme/secret_device/dumpstate/ hardware/interfaces/dumpstate
@@ -23,27 +24,42 @@
 ## To build, deploy, and take a bugreport
 
 ```
-mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb shell am bug-report
+mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb push ${OUT}/system/lib64/*dumpstate*.so /system/lib64/ && adb shell am bug-report
 ```
 
+Make sure that the device is remounted before running the above command. * If
+you're working with `userdebug` variant, you may need to run the following to
+remount your device:
+
+```
+  adb root && adb remount -R && adb wait-for-device && adb root && adb remount
+```
+
+*   If you're working with `eng` variant, you may need to run the following to
+    remount your device:
+
+    ```
+    adb root && adb remount
+    ```
+
 ## To build, deploy, and run unit tests
 
-First create `/data/nativetest`:
+First create `/data/nativetest64`:
 
 ```
-adb shell mkdir /data/nativetest
+adb shell mkdir /data/nativetest64
 ```
 
 Then run:
 
 ```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
 ```
 
 And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`):
 
 ```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs
 ```
 
 ## To take quick bugreports
@@ -52,6 +68,12 @@
 adb shell setprop dumpstate.dry_run true
 ```
 
+## To emulate a device with user build
+
+```
+adb shell setprop dumpstate.unroot true
+```
+
 ## To change the `dumpstate` version
 
 ```
@@ -64,7 +86,6 @@
 adb shell setprop dumpstate.version split-dumpsys && adb shell dumpstate -v
 ```
 
-
 Then to restore the default version:
 
 ```
@@ -73,8 +94,9 @@
 
 ## Code style and formatting
 
-Use the style defined at the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
-and make sure to run the following command prior to `repo upload`:
+Use the style defined at the
+[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
+make sure to run the following command prior to `repo upload`:
 
 ```
 git clang-format --style=file HEAD~
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 9b11b96..347856d 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -24,7 +24,7 @@
   * {@hide}
   */
 interface IDumpstate {
-
+    // TODO: remove method once startBugReport is used by Shell.
     /*
      * Sets the listener for this dumpstate progress.
      *
@@ -35,4 +35,54 @@
      */
     IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
                                 boolean getSectionDetails);
+
+    // NOTE: If you add to or change these modes, please also change the corresponding enums
+    // in system server, in BugreportParams.java.
+
+    // These modes encapsulate a set of run time options for generating bugreports.
+    // Takes a bugreport without user interference.
+    const int BUGREPORT_MODE_FULL = 0;
+
+    // Interactive bugreport, i.e. triggered by the user.
+    const int BUGREPORT_MODE_INTERACTIVE = 1;
+
+    // Remote bugreport triggered by DevicePolicyManager, for e.g.
+    const int BUGREPORT_MODE_REMOTE = 2;
+
+    // Bugreport triggered on a wear device.
+    const int BUGREPORT_MODE_WEAR = 3;
+
+    // Bugreport limited to only telephony info.
+    const int BUGREPORT_MODE_TELEPHONY = 4;
+
+    // Bugreport limited to only wifi info.
+    const int BUGREPORT_MODE_WIFI = 5;
+
+    // Default mode.
+    const int BUGREPORT_MODE_DEFAULT = 6;
+
+    /*
+     * Starts a bugreport in the background.
+     *
+     *<p>Shows the user a dialog to get consent for sharing the bugreport with the calling
+     * application. If they deny {@link IDumpstateListener#onError} will be called. If they
+     * consent and bugreport generation is successful artifacts will be copied to the given fds and
+     * {@link IDumpstateListener#onFinished} will be called. If there
+     * are errors in bugreport generation {@link IDumpstateListener#onError} will be called.
+     *
+     * @param callingUid UID of the original application that requested the report.
+     * @param callingPackage package of the original application that requested the report.
+     * @param bugreportFd the file to which the zipped bugreport should be written
+     * @param screenshotFd the file to which screenshot should be written; optional
+     * @param bugreportMode the mode that specifies other run time options; must be one of above
+     * @param listener callback for updates; optional
+     */
+    void startBugreport(int callingUid, @utf8InCpp String callingPackage,
+                        FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+                        int bugreportMode, IDumpstateListener listener);
+
+    /*
+     * Cancels the bugreport currently in progress.
+     */
+    void cancelBugreport();
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 030d69d..ea1e467 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -19,21 +19,63 @@
 /**
   * Listener for dumpstate events.
   *
+  * <p>When bugreport creation is complete one of {@code onError} or {@code onFinished} is called.
+  *
+  * <p>These methods are synchronous by design in order to make dumpstate's lifecycle simpler
+  * to handle.
+  *
   * {@hide}
   */
 interface IDumpstateListener {
+    /**
+     * Called when there is a progress update.
+     *
+     * @param progress the progress in [0, 100]
+     */
+    void onProgress(int progress);
+
+    // NOTE: If you add to or change these error codes, please also change the corresponding enums
+    // in system server, in BugreportManager.java.
+
+    /* Options specified are invalid or incompatible */
+    const int BUGREPORT_ERROR_INVALID_INPUT = 1;
+
+    /* Bugreport encountered a runtime error */
+    const int BUGREPORT_ERROR_RUNTIME_ERROR = 2;
+
+    /* User denied consent to share the bugreport with the specified app */
+    const int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3;
+
+    /* The request to get user consent timed out */
+    const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
+
+    /* There is currently a bugreport running. The caller should try again later. */
+    const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5;
+
+    /**
+     * Called on an error condition with one of the error codes listed above.
+     */
+    void onError(int errorCode);
+
+    /**
+     * Called when taking bugreport finishes successfully.
+     */
+    void onFinished();
+
+    // TODO(b/111441001): Remove old methods when not used anymore.
     void onProgressUpdated(int progress);
     void onMaxProgressUpdated(int maxProgress);
 
     /**
-    * Called after every section is complete.
-    * @param  name          section name
-    * @param  status        values from status_t
-    *                       {@code OK} section completed successfully
-    *                       {@code TIMEOUT} dump timed out
-    *                       {@code != OK} error
-    * @param  size          size in bytes, may be invalid if status != OK
-    * @param  durationMs    duration in ms
-    */
+     * Called after every section is complete.
+     *
+     * @param  name          section name
+     * @param  status        values from status_t
+     *                       {@code OK} section completed successfully
+     *                       {@code TIMEOUT} dump timed out
+     *                       {@code != OK} error
+     * @param  size          size in bytes, may be invalid if status != OK
+     * @param  durationMs    duration in ms
+     */
     void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1d951be..4ac7b68 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <libgen.h>
 #include <limits.h>
 #include <stdbool.h>
@@ -34,6 +35,7 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <fstream>
 #include <functional>
 #include <future>
 #include <memory>
@@ -49,11 +51,16 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <android/content/pm/IPackageManagerNative.h>
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/os/IIncidentCompanion.h>
+#include <binder/IServiceManager.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
+#include <debuggerd/client.h>
 #include <dumpsys.h>
+#include <dumputils/dump_utils.h>
 #include <hidl/ServiceManagement.h>
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
@@ -82,15 +89,20 @@
 using android::TIMED_OUT;
 using android::UNKNOWN_ERROR;
 using android::Vector;
+using android::base::StringPrintf;
+using android::os::IDumpstateListener;
 using android::os::dumpstate::CommandOptions;
 using android::os::dumpstate::DumpFileToFd;
 using android::os::dumpstate::DumpstateSectionReporter;
 using android::os::dumpstate::GetPidByName;
 using android::os::dumpstate::PropertiesHelper;
 
+typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
+
 /* read before root is shed */
 static char cmdline_buf[16384] = "(unknown)";
-static const char *dump_traces_path = NULL;
+static const char *dump_traces_path = nullptr;
+static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
 
 // TODO: variables and functions below should be part of dumpstate object
 
@@ -101,13 +113,13 @@
 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
 #define BLK_DEV_SYS_DIR "/sys/block"
 
-#define RAFT_DIR "/data/misc/raft"
 #define RECOVERY_DIR "/cache/recovery"
 #define RECOVERY_DATA_DIR "/data/misc/recovery"
 #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
+#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
 #define WLUTIL "/vendor/xbin/wlutil"
 #define WMTRACE_DATA_DIR "/data/misc/wmtrace"
 
@@ -122,6 +134,107 @@
 
 // TODO: temporary variables and functions used during C++ refactoring
 static Dumpstate& ds = Dumpstate::GetInstance();
+
+#define RETURN_IF_USER_DENIED_CONSENT()                                                        \
+    if (ds.IsUserConsentDenied()) {                                                            \
+        MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \
+        return Dumpstate::RunStatus::USER_CONSENT_DENIED;                                      \
+    }
+
+// Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED
+// if consent is found to be denied.
+#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \
+    RETURN_IF_USER_DENIED_CONSENT();                        \
+    func_ptr(__VA_ARGS__);                                  \
+    RETURN_IF_USER_DENIED_CONSENT();
+
+namespace android {
+namespace os {
+namespace {
+
+static int Open(std::string path, int flags, mode_t mode = 0) {
+    int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
+    if (fd == -1) {
+        MYLOGE("open(%s, %s)\n", path.c_str(), strerror(errno));
+    }
+    return fd;
+}
+
+
+static int OpenForRead(std::string path) {
+    return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+}
+
+bool CopyFile(int in_fd, int out_fd) {
+    char buf[4096];
+    ssize_t byte_count;
+    while ((byte_count = TEMP_FAILURE_RETRY(read(in_fd, buf, sizeof(buf)))) > 0) {
+        if (!android::base::WriteFully(out_fd, buf, byte_count)) {
+            return false;
+        }
+    }
+    return (byte_count != -1);
+}
+
+static bool CopyFileToFd(const std::string& input_file, int out_fd) {
+    MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
+
+    // Obtain a handle to the source file.
+    android::base::unique_fd in_fd(OpenForRead(input_file));
+    if (out_fd != -1 && in_fd.get() != -1) {
+        if (CopyFile(in_fd.get(), out_fd)) {
+            return true;
+        }
+        MYLOGE("Failed to copy file: %s\n", strerror(errno));
+    }
+    return false;
+}
+
+static bool UnlinkAndLogOnError(const std::string& file) {
+    if (unlink(file.c_str())) {
+        MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+static bool IsFileEmpty(const std::string& file_path) {
+    std::ifstream file(file_path, std::ios::binary | std::ios::ate);
+    if(file.bad()) {
+        MYLOGE("Cannot open file: %s\n", file_path.c_str());
+        return true;
+    }
+    return file.tellg() <= 0;
+}
+
+int64_t GetModuleMetadataVersion() {
+    auto binder = defaultServiceManager()->getService(android::String16("package_native"));
+    if (binder == nullptr) {
+        MYLOGE("Failed to retrieve package_native service");
+        return 0L;
+    }
+    auto package_service = android::interface_cast<content::pm::IPackageManagerNative>(binder);
+    std::string package_name;
+    auto status = package_service->getModuleMetadataPackageName(&package_name);
+    if (!status.isOk()) {
+        MYLOGE("Failed to retrieve module metadata package name: %s", status.toString8().c_str());
+        return 0L;
+    }
+    MYLOGD("Module metadata package name: %s", package_name.c_str());
+    int64_t version_code;
+    status = package_service->getVersionCodeForPackage(android::String16(package_name.c_str()),
+                                                       &version_code);
+    if (!status.isOk()) {
+        MYLOGE("Failed to retrieve module metadata version: %s", status.toString8().c_str());
+        return 0L;
+    }
+    return version_code;
+}
+
+}  // namespace
+}  // namespace os
+}  // namespace android
+
 static int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
                       const CommandOptions& options = CommandOptions::DEFAULT) {
     return ds.RunCommand(title, fullCommand, options);
@@ -138,8 +251,6 @@
 // Relative directory (inside the zip) for all files copied as-is into the bugreport.
 static const std::string ZIP_ROOT_DIR = "FS";
 
-// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/";
 static const std::string kProtoPath = "proto/";
 static const std::string kProtoExt = ".proto";
 static const std::string kDumpstateBoardFiles[] = {
@@ -295,7 +406,7 @@
     char path[PATH_MAX];
 
     d = opendir(driverpath);
-    if (d == NULL) {
+    if (d == nullptr) {
         return;
     }
 
@@ -333,7 +444,7 @@
     }
 
     // find anrd's pid if it is running.
-    pid = GetPidByName("/system/xbin/anrd");
+    pid = GetPidByName("/system/bin/anrd");
 
     if (pid > 0) {
         if (stat(trace_path, &st) == 0) {
@@ -402,9 +513,7 @@
             if (!ds.AddZipEntry("anrd_trace.txt", path)) {
                 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
             } else {
-                if (remove(path)) {
-                    MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
-                }
+                android::os::UnlinkAndLogOnError(path);
                 return true;
             }
         } else {
@@ -414,81 +523,6 @@
     return false;
 }
 
-static void dump_systrace() {
-    if (!ds.IsZipping()) {
-        MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
-        return;
-    }
-    std::string systrace_path = ds.GetPath("-systrace.txt");
-    if (systrace_path.empty()) {
-        MYLOGE("Not dumping systrace because path is empty\n");
-        return;
-    }
-    const char* path = "/sys/kernel/debug/tracing/tracing_on";
-    long int is_tracing;
-    if (read_file_as_long(path, &is_tracing)) {
-        return; // error already logged
-    }
-    if (is_tracing <= 0) {
-        MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
-        return;
-    }
-
-    MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
-            systrace_path.c_str());
-    if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
-                   CommandOptions::WithTimeout(120).Build())) {
-        MYLOGE("systrace timed out, its zip entry will be incomplete\n");
-        // TODO: RunCommand tries to kill the process, but atrace doesn't die
-        // peacefully; ideally, we should call strace to stop itself, but there is no such option
-        // yet (just a --async_stop, which stops and dump
-        // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
-        //   MYLOGE("could not stop systrace ");
-        // }
-    }
-    if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
-        MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
-    } else {
-        if (remove(systrace_path.c_str())) {
-            MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
-        }
-    }
-}
-
-static void dump_raft() {
-    if (PropertiesHelper::IsUserBuild()) {
-        return;
-    }
-
-    std::string raft_path = ds.GetPath("-raft_log.txt");
-    if (raft_path.empty()) {
-        MYLOGD("raft_path is empty\n");
-        return;
-    }
-
-    struct stat s;
-    if (stat(RAFT_DIR, &s) != 0 || !S_ISDIR(s.st_mode)) {
-        MYLOGD("%s does not exist or is not a directory\n", RAFT_DIR);
-        return;
-    }
-
-    CommandOptions options = CommandOptions::WithTimeout(600).Build();
-    if (!ds.IsZipping()) {
-        // Write compressed and encoded raft logs to stdout if it's not a zipped bugreport.
-        RunCommand("RAFT LOGS", {"logcompressor", "-r", RAFT_DIR}, options);
-        return;
-    }
-
-    RunCommand("RAFT LOGS", {"logcompressor", "-n", "-r", RAFT_DIR, "-o", raft_path}, options);
-    if (!ds.AddZipEntry("raft_log.txt", raft_path)) {
-        MYLOGE("Unable to add raft log %s to zip file\n", raft_path.c_str());
-    } else {
-        if (remove(raft_path.c_str())) {
-            MYLOGE("Error removing raft file %s: %s\n", raft_path.c_str(), strerror(errno));
-        }
-    }
-}
-
 static bool skip_not_stat(const char *path) {
     static const char stat[] = "/stat";
     size_t len = strlen(path);
@@ -587,9 +621,9 @@
 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
     unsigned long long fields[__STAT_NUMBER_FIELD];
     bool z;
-    char *cp, *buffer = NULL;
+    char *cp, *buffer = nullptr;
     size_t i = 0;
-    FILE *fp = fdopen(fd, "rb");
+    FILE *fp = fdopen(dup(fd), "rb");
     getline(&buffer, &i, fp);
     fclose(fp);
     if (!buffer) {
@@ -686,6 +720,32 @@
     return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
 }
 
+Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
+}
+
+android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
+    std::lock_guard<std::mutex> lock(lock_);
+    result_ = APPROVED;
+    MYLOGD("User approved consent to share bugreport\n");
+    return android::binder::Status::ok();
+}
+
+android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
+    std::lock_guard<std::mutex> lock(lock_);
+    result_ = DENIED;
+    MYLOGW("User denied consent to share bugreport\n");
+    return android::binder::Status::ok();
+}
+
+UserConsentResult Dumpstate::ConsentCallback::getResult() {
+    std::lock_guard<std::mutex> lock(lock_);
+    return result_;
+}
+
+uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
+    return Nanotime() - start_time_;
+}
+
 void Dumpstate::PrintHeader() const {
     std::string build, fingerprint, radio, bootloader, network;
     char date[80];
@@ -708,6 +768,10 @@
     printf("Bootloader: %s\n", bootloader.c_str());
     printf("Radio: %s\n", radio.c_str());
     printf("Network: %s\n", network.c_str());
+    int64_t module_metadata_version = android::os::GetModuleMetadataVersion();
+    if (module_metadata_version != 0) {
+        printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
+    }
 
     printf("Kernel: ");
     DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
@@ -717,7 +781,7 @@
                    CommandOptions::WithTimeout(1).Always().Build());
     printf("Bugreport format version: %s\n", version_.c_str());
     printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
-           PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
+           PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
     printf("\n");
 }
 
@@ -758,6 +822,17 @@
                ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
     }
+    bool finished_entry = false;
+    auto finish_entry = [this, &finished_entry] {
+        if (!finished_entry) {
+            // This should only be called when we're going to return an earlier error,
+            // which would've been logged. This may imply the file is already corrupt
+            // and any further logging from FinishEntry is more likely to mislead than
+            // not.
+            this->zip_writer_->FinishEntry();
+        }
+    };
+    auto scope_guard = android::base::make_scope_guard(finish_entry);
     auto start = std::chrono::steady_clock::now();
     auto end = start + timeout;
     struct pollfd pfd = {fd, POLLIN};
@@ -774,11 +849,11 @@
 
             int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
             if (rc < 0) {
-                MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
-                       strerror(errno));
+                MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
+                       entry_name.c_str(), strerror(errno));
                 return -errno;
             } else if (rc == 0) {
-                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
                        entry_name.c_str(), strerror(errno), timeout.count());
                 return TIMED_OUT;
             }
@@ -799,6 +874,7 @@
     }
 
     err = zip_writer_->FinishEntry();
+    finished_entry = true;
     if (err != 0) {
         MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
@@ -926,53 +1002,6 @@
     RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
 }
 
-static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file,
-                                  const std::string& anr_traces_dir) {
-    std::string dump_traces_dir;
-
-    if (dump_traces_path != nullptr) {
-        if (add_to_zip) {
-            dump_traces_dir = dirname(dump_traces_path);
-            MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str());
-            ds.AddDir(dump_traces_dir, true);
-        } else {
-            MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
-                   dump_traces_path);
-            ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
-        }
-    }
-
-
-    // Make sure directory is not added twice.
-    // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
-    // generated by dump_traces() -  and anr_traces_path - which is retrieved from a system
-    // property - but in reality they're the same path (although the former could be nullptr).
-    // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should
-    // be revisited.
-    bool already_dumped = anr_traces_dir == dump_traces_dir;
-
-    MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
-           dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
-
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
-    if (fd.get() < 0) {
-        printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
-    } else {
-        if (add_to_zip) {
-            if (!already_dumped) {
-                MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
-                       anr_traces_dir.c_str());
-                ds.AddDir(anr_traces_dir, true);
-            }
-        } else {
-            MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
-                   anr_traces_file.c_str());
-            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
-        }
-    }
-}
-
 static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
     MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
            anr_traces_dir.c_str());
@@ -1015,50 +1044,24 @@
 static void AddAnrTraceFiles() {
     const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
 
-    std::string anr_traces_file;
-    std::string anr_traces_dir;
-    bool is_global_trace_file = true;
+    std::string anr_traces_dir = "/data/anr";
 
-    // First check whether the stack-trace-dir property is set. When it's set,
-    // each ANR trace will be written to a separate file and not to a global
-    // stack trace file.
-    anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
-    if (anr_traces_dir.empty()) {
-        anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
-        if (!anr_traces_file.empty()) {
-            anr_traces_dir = dirname(anr_traces_file.c_str());
-        }
-    } else {
-        is_global_trace_file = false;
-    }
+    AddAnrTraceDir(add_to_zip, anr_traces_dir);
 
-    // We have neither configured a global trace file nor a trace directory,
-    // there will be nothing to dump.
-    if (anr_traces_file.empty() && anr_traces_dir.empty()) {
-        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
-        return;
-    }
+    RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
 
-    if (is_global_trace_file) {
-        AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir);
-    } else {
-        AddAnrTraceDir(add_to_zip, anr_traces_dir);
-    }
-
-    /* slow traces for slow operations */
+    // Slow traces for slow operations.
     struct stat st;
-    if (!anr_traces_dir.empty()) {
-        int i = 0;
-        while (true) {
-            const std::string slow_trace_path =
-                anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
-            if (stat(slow_trace_path.c_str(), &st)) {
-                // No traces file at this index, done with the files.
-                break;
-            }
-            ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
-            i++;
+    int i = 0;
+    while (true) {
+        const std::string slow_trace_path =
+            anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
+        if (stat(slow_trace_path.c_str(), &st)) {
+            // No traces file at this index, done with the files.
+            break;
         }
+        ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
+        i++;
     }
 }
 
@@ -1105,9 +1108,9 @@
     RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
 }
 
-static void RunDumpsysTextByPriority(const std::string& title, int priority,
-                                     std::chrono::milliseconds timeout,
-                                     std::chrono::milliseconds service_timeout) {
+static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority,
+                                                     std::chrono::milliseconds timeout,
+                                                     std::chrono::milliseconds service_timeout) {
     auto start = std::chrono::steady_clock::now();
     sp<android::IServiceManager> sm = defaultServiceManager();
     Dumpsys dumpsys(sm.get());
@@ -1115,6 +1118,7 @@
     Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
     Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
     for (const String16& service : services) {
+        RETURN_IF_USER_DENIED_CONSENT();
         std::string path(title);
         path.append(" - ").append(String8(service).c_str());
         DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
@@ -1140,6 +1144,7 @@
             break;
         }
     }
+    return Dumpstate::RunStatus::OK;
 }
 
 static void RunDumpsysText(const std::string& title, int priority,
@@ -1152,24 +1157,27 @@
 }
 
 /* Dump all services registered with Normal or Default priority. */
-static void RunDumpsysTextNormalPriority(const std::string& title,
-                                         std::chrono::milliseconds timeout,
-                                         std::chrono::milliseconds service_timeout) {
+static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title,
+                                                         std::chrono::milliseconds timeout,
+                                                         std::chrono::milliseconds service_timeout) {
     DurationReporter duration_reporter(title);
     dprintf(STDOUT_FILENO, "------ %s (/system/bin/dumpsys) ------\n", title.c_str());
     fsync(STDOUT_FILENO);
     RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout,
                              service_timeout);
-    RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
-                             service_timeout);
+
+    RETURN_IF_USER_DENIED_CONSENT();
+
+    return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout,
+                                    service_timeout);
 }
 
-static void RunDumpsysProto(const std::string& title, int priority,
-                            std::chrono::milliseconds timeout,
-                            std::chrono::milliseconds service_timeout) {
+static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
+                                            std::chrono::milliseconds timeout,
+                                            std::chrono::milliseconds service_timeout) {
     if (!ds.IsZipping()) {
         MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
-        return;
+        return Dumpstate::RunStatus::OK;
     }
     sp<android::IServiceManager> sm = defaultServiceManager();
     Dumpsys dumpsys(sm.get());
@@ -1180,6 +1188,7 @@
     auto start = std::chrono::steady_clock::now();
     Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
     for (const String16& service : services) {
+        RETURN_IF_USER_DENIED_CONSENT();
         std::string path(kProtoPath);
         path.append(String8(service).c_str());
         if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
@@ -1208,35 +1217,54 @@
             break;
         }
     }
+    return Dumpstate::RunStatus::OK;
 }
 
-// Runs dumpsys on services that must dump first and and will take less than 100ms to dump.
-static void RunDumpsysCritical() {
+// Runs dumpsys on services that must dump first and will take less than 100ms to dump.
+static Dumpstate::RunStatus RunDumpsysCritical() {
     RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
                    /* timeout= */ 5s, /* service_timeout= */ 500ms);
-    RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
-                    /* timeout= */ 5s, /* service_timeout= */ 500ms);
+
+    RETURN_IF_USER_DENIED_CONSENT();
+
+    return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
+                           /* timeout= */ 5s, /* service_timeout= */ 500ms);
 }
 
 // Runs dumpsys on services that must dump first but can take up to 250ms to dump.
-static void RunDumpsysHigh() {
+static Dumpstate::RunStatus RunDumpsysHigh() {
     // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
     // high priority. Reduce timeout once they are able to dump in a shorter time or
     // moved to a parallel task.
     RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
                    /* timeout= */ 90s, /* service_timeout= */ 30s);
-    RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
-                    /* timeout= */ 5s, /* service_timeout= */ 1s);
+
+    RETURN_IF_USER_DENIED_CONSENT();
+
+    return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
+                           /* timeout= */ 5s, /* service_timeout= */ 1s);
 }
 
 // Runs dumpsys on services that must dump but can take up to 10s to dump.
-static void RunDumpsysNormal() {
+static Dumpstate::RunStatus RunDumpsysNormal() {
     RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s);
-    RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
-                    /* timeout= */ 90s, /* service_timeout= */ 10s);
+
+    RETURN_IF_USER_DENIED_CONSENT();
+
+    return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
+                           /* timeout= */ 90s, /* service_timeout= */ 10s);
 }
 
 static void DumpHals() {
+    if (!ds.IsZipping()) {
+        RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
+                   CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+        return;
+    }
+    DurationReporter duration_reporter("DUMP HALS");
+    RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
+               CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+
     using android::hidl::manager::V1_0::IServiceManager;
     using android::hardware::defaultServiceManager;
 
@@ -1255,7 +1283,7 @@
                                 return !isalnum(c) &&
                                     std::string("@-_:.").find(c) == std::string::npos;
                             }, '_');
-            const std::string path = kDumpstateBoardPath + "lshal_debug_" + cleanName;
+            const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
 
             {
                 auto fd = android::base::unique_fd(
@@ -1286,9 +1314,16 @@
     }
 }
 
-static void dumpstate() {
+// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
+// via the consent they are shown. Ignores other errors that occur while running various
+// commands. The consent checking is currently done around long running tasks, which happen to
+// be distributed fairly evenly throughout the function.
+static Dumpstate::RunStatus dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
+    // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
+    // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
+    // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
     RunCommand("UPTIME", {"uptime"});
     DumpBlockStatFiles();
@@ -1296,7 +1331,9 @@
     DumpFile("MEMORY INFO", "/proc/meminfo");
     RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
                             "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});
-    RunCommand("PROCRANK", {"procrank"}, AS_ROOT_20);
+
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);
+
     DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
     DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
     DumpFile("SLAB INFO", "/proc/slabinfo");
@@ -1311,14 +1348,11 @@
 
     RunCommand("PROCESSES AND THREADS",
                {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
-    RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
 
-    if (ds.IsZipping()) {
-        RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
-        DumpHals();
-    } else {
-        RunCommand("HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
-    }
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
+                                         CommandOptions::AS_ROOT);
+
+    DumpHals();
 
     RunCommand("PRINTENV", {"printenv"});
     RunCommand("NETSTAT", {"netstat", "-nW"});
@@ -1337,7 +1371,9 @@
     }
 
     RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
-    for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
+
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");
+
     for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
     for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
 
@@ -1363,6 +1399,8 @@
 
     DumpPacketStats();
 
+    RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});
+
     DoKmsg();
 
     DumpIpAddrAndRules();
@@ -1373,7 +1411,7 @@
     RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
     RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
 
-    RunDumpsysHigh();
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
@@ -1390,12 +1428,13 @@
     DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
     DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
 
+    RunDumpsys("WINSCOPE TRACE", {"window", "trace"});
     /* Add window and surface trace files. */
     if (!PropertiesHelper::IsUserBuild()) {
         ds.AddDir(WMTRACE_DATA_DIR, false);
     }
 
-    ds.DumpstateBoard();
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
 
     /* Migrate the ril_dumpstate to a device specific dumpstate? */
     int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
@@ -1415,14 +1454,16 @@
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    RunDumpsysNormal();
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
 
     printf("========================================================\n");
     printf("== Checkins\n");
     printf("========================================================\n");
 
     RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
-    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"});
+
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
+
     RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
     RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
     RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
@@ -1443,7 +1484,7 @@
     printf("== Running Application Services (platform)\n");
     printf("========================================================\n");
 
-    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform"},
+    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
             DUMPSYS_COMPONENTS_OPTIONS);
 
     printf("========================================================\n");
@@ -1480,6 +1521,73 @@
     printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
+
+    printf("========================================================\n");
+    printf("== Obtaining statsd metadata\n");
+    printf("========================================================\n");
+    // This differs from the usual dumpsys stats, which is the stats report data.
+    RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
+    return Dumpstate::RunStatus::OK;
+}
+
+/*
+ * Dumps state for the default case; drops root after it's no longer necessary.
+ *
+ * Returns RunStatus::OK if everything went fine.
+ * Returns RunStatus::ERROR if there was an error.
+ * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
+ * with the caller.
+ */
+static Dumpstate::RunStatus DumpstateDefault() {
+    // Try to dump anrd trace if the daemon is running.
+    dump_anrd_trace();
+
+    // Invoking the following dumpsys calls before DumpTraces() to try and
+    // keep the system stats as close to its initial state as possible.
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
+
+    /* collect stack traces from Dalvik and native processes (needs root) */
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
+
+    /* Run some operations that require root. */
+    ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
+    ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+
+    ds.AddDir(RECOVERY_DIR, true);
+    ds.AddDir(RECOVERY_DATA_DIR, true);
+    ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
+    ds.AddDir(LOGPERSIST_DATA_DIR, false);
+    if (!PropertiesHelper::IsUserBuild()) {
+        ds.AddDir(PROFILE_DATA_DIR_CUR, true);
+        ds.AddDir(PROFILE_DATA_DIR_REF, true);
+    }
+    add_mountinfo();
+    DumpIpTablesAsRoot();
+
+    // Capture any IPSec policies in play. No keys are exposed here.
+    RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
+
+    // Dump IPsec stats. No keys are exposed here.
+    DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
+
+    // Run ss as root so we can see socket marks.
+    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"});
+
+    // Gather shared memory buffer info if the product implements it
+    struct stat st;
+    if (!stat("/product/bin/dmabuf_dump", &st)) {
+        RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
+    }
+
+    if (!DropRootUser()) {
+        return Dumpstate::RunStatus::ERROR;
+    }
+
+    RETURN_IF_USER_DENIED_CONSENT();
+    return dumpstate();
 }
 
 // This method collects common dumpsys for telephony and wifi
@@ -1516,6 +1624,9 @@
 
     RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
     RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
@@ -1562,11 +1673,123 @@
     RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
 
+    DumpHals();
+
     printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
 }
 
+Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
+    DurationReporter duration_reporter("DUMP TRACES");
+
+    const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
+    const size_t buf_size = temp_file_pattern.length() + 1;
+    std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
+    memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
+
+    // Create a new, empty file to receive all trace dumps.
+    //
+    // TODO: This can be simplified once we remove support for the old style
+    // dumps. We can have a file descriptor passed in to dump_traces instead
+    // of creating a file, closing it and then reopening it again.
+    android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
+    if (fd < 0) {
+        MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
+        return RunStatus::OK;
+    }
+
+    // Nobody should have access to this temporary file except dumpstate, but we
+    // temporarily grant 'read' to 'others' here because this file is created
+    // when tombstoned is still running as root, but dumped after dropping. This
+    // can go away once support for old style dumping has.
+    const int chmod_ret = fchmod(fd, 0666);
+    if (chmod_ret < 0) {
+        MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
+        return RunStatus::OK;
+    }
+
+    std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+    if (proc.get() == nullptr) {
+        MYLOGE("opendir /proc failed: %s\n", strerror(errno));
+        return RunStatus::OK;
+    }
+
+    // Number of times process dumping has timed out. If we encounter too many
+    // failures, we'll give up.
+    int timeout_failures = 0;
+    bool dalvik_found = false;
+
+    const std::set<int> hal_pids = get_interesting_hal_pids();
+
+    struct dirent* d;
+    while ((d = readdir(proc.get()))) {
+        RETURN_IF_USER_DENIED_CONSENT();
+        int pid = atoi(d->d_name);
+        if (pid <= 0) {
+            continue;
+        }
+
+        const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
+        std::string exe;
+        if (!android::base::Readlink(link_name, &exe)) {
+            continue;
+        }
+
+        bool is_java_process;
+        if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+            // Don't bother dumping backtraces for the zygote.
+            if (IsZygote(pid)) {
+                continue;
+            }
+
+            dalvik_found = true;
+            is_java_process = true;
+        } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
+            is_java_process = false;
+        } else {
+            // Probably a native process we don't care about, continue.
+            continue;
+        }
+
+        // If 3 backtrace dumps fail in a row, consider debuggerd dead.
+        if (timeout_failures == 3) {
+            dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
+            break;
+        }
+
+        const uint64_t start = Nanotime();
+        const int ret = dump_backtrace_to_file_timeout(
+            pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
+            is_java_process ? 5 : 20, fd);
+
+        if (ret == -1) {
+            // For consistency, the header and footer to this message match those
+            // dumped by debuggerd in the success case.
+            dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
+            dprintf(fd, "Dump failed, likely due to a timeout.\n");
+            dprintf(fd, "---- end %d ----", pid);
+            timeout_failures++;
+            continue;
+        }
+
+        // We've successfully dumped stack traces, reset the failure count
+        // and write a summary of the elapsed time to the file and continue with the
+        // next process.
+        timeout_failures = 0;
+
+        dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
+                pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
+    }
+
+    if (!dalvik_found) {
+        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
+    }
+
+    *path = file_name_buf.release();
+    return RunStatus::OK;
+}
+
 void Dumpstate::DumpstateBoard() {
     DurationReporter duration_reporter("dumpstate_board()");
     printf("========================================================\n");
@@ -1581,14 +1804,10 @@
     std::vector<std::string> paths;
     std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
-        paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]);
-        remover.emplace_back(android::base::make_scope_guard(std::bind(
-            [](std::string path) {
-                if (remove(path.c_str()) != 0 && errno != ENOENT) {
-                    MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
-                }
-            },
-            paths[i])));
+        paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
+                                        kDumpstateBoardFiles[i].c_str()));
+        remover.emplace_back(android::base::make_scope_guard(
+            std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
     }
 
     sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
@@ -1609,6 +1828,7 @@
         return;
     }
 
+    // TODO(128270426): Check for consent in between?
     for (size_t i = 0; i < paths.size(); i++) {
         MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
 
@@ -1681,7 +1901,7 @@
     printf("*** See dumpstate-board.txt entry ***\n");
 }
 
-static void ShowUsageAndExit(int exitCode = 1) {
+static void ShowUsage() {
     fprintf(stderr,
             "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1700,13 +1920,8 @@
             "progress (requires -o and -B)\n"
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
+            "  -w: start binder service and make it wait for a call to startBugreport\n"
             "  -v: prints the dumpstate header and exit\n");
-    exit(exitCode);
-}
-
-static void ExitOnInvalidArgs() {
-    fprintf(stderr, "invalid combination of args\n");
-    ShowUsageAndExit();
 }
 
 static void register_sig_handler() {
@@ -1739,8 +1954,11 @@
         MYLOGE("Failed to add dumpstate log to .zip file\n");
         return false;
     }
-    // ... and re-opens it for further logging.
-    redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
+    // TODO: Should truncate the existing file.
+    // ... and re-open it for further logging.
+    if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
+        return false;
+    }
     fprintf(stderr, "\n");
 
     int32_t err = zip_writer_->Finish();
@@ -1753,9 +1971,7 @@
     ds.zip_file.reset(nullptr);
 
     MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
-    if (remove(tmp_path_.c_str()) != 0) {
-        MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
-    }
+    android::os::UnlinkAndLogOnError(tmp_path_);
 
     return true;
 }
@@ -1765,7 +1981,7 @@
             | O_CLOEXEC | O_NOFOLLOW)));
     if (fd == -1) {
         MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
-        return NULL;
+        return nullptr;
     }
 
     SHA256_CTX ctx;
@@ -1778,7 +1994,7 @@
             break;
         } else if (bytes_read == -1) {
             MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
-            return NULL;
+            return nullptr;
         }
 
         SHA256_Update(&ctx, buffer.data(), bytes_read);
@@ -1822,24 +2038,466 @@
     // clang-format on
 }
 
-/** Main entry point for dumpstate. */
-int run_main(int argc, char* argv[]) {
-    int do_add_date = 0;
-    int do_zip_file = 0;
-    int do_vibrate = 1;
-    char* use_outfile = 0;
-    int use_socket = 0;
-    int use_control_socket = 0;
-    int do_fb = 0;
-    int do_broadcast = 0;
-    int is_remote_mode = 0;
-    bool show_header_only = false;
-    bool do_start_service = false;
-    bool telephony_only = false;
-    bool wifi_only = false;
-    int dup_stdout_fd;
-    int dup_stderr_fd;
+static void MaybeResolveSymlink(std::string* path) {
+    std::string resolved_path;
+    if (android::base::Readlink(*path, &resolved_path)) {
+        *path = resolved_path;
+    }
+}
 
+/*
+ * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
+ * if we are writing zip files and adds the version file.
+ */
+static void PrepareToWriteToFile() {
+    MaybeResolveSymlink(&ds.bugreport_internal_dir_);
+
+    std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
+    std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
+    ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
+    if (ds.options_->do_add_date) {
+        char date[80];
+        strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+        ds.name_ = date;
+    } else {
+        ds.name_ = "undated";
+    }
+
+    if (ds.options_->telephony_only) {
+        ds.base_name_ += "-telephony";
+    } else if (ds.options_->wifi_only) {
+        ds.base_name_ += "-wifi";
+    }
+
+    if (ds.options_->do_fb) {
+        ds.screenshot_path_ = ds.GetPath(".png");
+    }
+    ds.tmp_path_ = ds.GetPath(".tmp");
+    ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
+
+    std::string destination = ds.options_->bugreport_fd.get() != -1
+                                  ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
+                                  : ds.bugreport_internal_dir_.c_str();
+    MYLOGD(
+        "Bugreport dir: %s\n"
+        "Base name: %s\n"
+        "Suffix: %s\n"
+        "Log path: %s\n"
+        "Temporary path: %s\n"
+        "Screenshot path: %s\n",
+        destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
+        ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
+
+    if (ds.options_->do_zip_file) {
+        ds.path_ = ds.GetPath(".zip");
+        MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
+        create_parent_dirs(ds.path_.c_str());
+        ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
+        if (ds.zip_file == nullptr) {
+            MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
+        } else {
+            ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
+        }
+        ds.AddTextZipEntry("version.txt", ds.version_);
+    }
+}
+
+/*
+ * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
+ * printing zipped file status, etc.
+ */
+static void FinalizeFile() {
+    /* check if user changed the suffix using system properties */
+    std::string name =
+        android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
+    bool change_suffix = false;
+    if (!name.empty()) {
+        /* must whitelist which characters are allowed, otherwise it could cross directories */
+        std::regex valid_regex("^[-_a-zA-Z0-9]+$");
+        if (std::regex_match(name.c_str(), valid_regex)) {
+            change_suffix = true;
+        } else {
+            MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
+        }
+    }
+    if (change_suffix) {
+        MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
+        ds.name_ = name;
+        if (!ds.screenshot_path_.empty()) {
+            std::string new_screenshot_path = ds.GetPath(".png");
+            if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
+                MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
+                       new_screenshot_path.c_str(), strerror(errno));
+            } else {
+                ds.screenshot_path_ = new_screenshot_path;
+            }
+        }
+    }
+
+    bool do_text_file = true;
+    if (ds.options_->do_zip_file) {
+        if (!ds.FinishZipFile()) {
+            MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
+            do_text_file = true;
+        } else {
+            do_text_file = false;
+            // If the user has changed the suffix, we need to change the zip file name.
+            std::string new_path = ds.GetPath(".zip");
+            if (ds.path_ != new_path) {
+                MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
+                if (rename(ds.path_.c_str(), new_path.c_str())) {
+                    MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
+                           strerror(errno));
+                } else {
+                    ds.path_ = new_path;
+                }
+            }
+        }
+    }
+    if (do_text_file) {
+        ds.path_ = ds.GetPath(".txt");
+        MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
+        if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
+            MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
+            ds.path_.clear();
+        }
+    }
+    if (ds.options_->use_control_socket) {
+        if (do_text_file) {
+            dprintf(ds.control_socket_fd_,
+                    "FAIL:could not create zip file, check %s "
+                    "for more details\n",
+                    ds.log_path_.c_str());
+        } else {
+            dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
+        }
+    }
+}
+
+/* Broadcasts that we are done with the bugreport */
+static void SendBugreportFinishedBroadcast() {
+    // TODO(b/111441001): use callback instead of broadcast.
+    if (!ds.path_.empty()) {
+        MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
+        // clang-format off
+
+        std::vector<std::string> am_args = {
+             "--receiver-permission", "android.permission.DUMP",
+             "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
+             "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
+             "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
+             "--es", "android.intent.extra.BUGREPORT", ds.path_,
+             "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
+        };
+        // clang-format on
+        if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
+            am_args.push_back("--es");
+            am_args.push_back("android.intent.extra.SCREENSHOT");
+            am_args.push_back(ds.screenshot_path_);
+        }
+        if (!ds.options_->notification_title.empty()) {
+            am_args.push_back("--es");
+            am_args.push_back("android.intent.extra.TITLE");
+            am_args.push_back(ds.options_->notification_title);
+            if (!ds.options_->notification_description.empty()) {
+                am_args.push_back("--es");
+                am_args.push_back("android.intent.extra.DESCRIPTION");
+                am_args.push_back(ds.options_->notification_description);
+            }
+        }
+        if (ds.options_->is_remote_mode) {
+            am_args.push_back("--es");
+            am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
+            am_args.push_back(SHA256_file_hash(ds.path_));
+            SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
+        } else {
+            SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
+        }
+    } else {
+        MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
+    }
+}
+
+static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
+    switch (mode) {
+        case Dumpstate::BugreportMode::BUGREPORT_FULL:
+            return "BUGREPORT_FULL";
+        case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+            return "BUGREPORT_INTERACTIVE";
+        case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+            return "BUGREPORT_REMOTE";
+        case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+            return "BUGREPORT_WEAR";
+        case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+            return "BUGREPORT_TELEPHONY";
+        case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+            return "BUGREPORT_WIFI";
+        case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+            return "BUGREPORT_DEFAULT";
+    }
+}
+
+static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
+    options->extra_options = ModeToString(mode);
+    switch (mode) {
+        case Dumpstate::BugreportMode::BUGREPORT_FULL:
+            options->do_broadcast = true;
+            options->do_fb = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+            // Currently, the dumpstate binder is only used by Shell to update progress.
+            options->do_start_service = true;
+            options->do_progress_updates = true;
+            options->do_fb = false;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+            options->do_vibrate = false;
+            options->is_remote_mode = true;
+            options->do_fb = false;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+            options->do_start_service = true;
+            options->do_progress_updates = true;
+            options->do_zip_file = true;
+            options->do_fb = true;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+            options->telephony_only = true;
+            options->do_fb = false;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+            options->wifi_only = true;
+            options->do_zip_file = true;
+            options->do_fb = false;
+            options->do_broadcast = true;
+            break;
+        case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+            break;
+    }
+}
+
+static Dumpstate::BugreportMode getBugreportModeFromProperty() {
+    // If the system property is not set, it's assumed to be a default bugreport.
+    Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
+
+    std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    if (!extra_options.empty()) {
+        // Framework uses a system property to override some command-line args.
+        // Currently, it contains the type of the requested bugreport.
+        if (extra_options == "bugreportplus") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
+        } else if (extra_options == "bugreportfull") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
+        } else if (extra_options == "bugreportremote") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
+        } else if (extra_options == "bugreportwear") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
+        } else if (extra_options == "bugreporttelephony") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
+        } else if (extra_options == "bugreportwifi") {
+            mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
+        } else {
+            MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
+        }
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    }
+    return mode;
+}
+
+// TODO: Move away from system properties when we have options passed via binder calls.
+/* Sets runtime options from the system properties and then clears those properties. */
+static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
+    Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
+    SetOptionsFromMode(mode, options);
+
+    options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+    if (!options->notification_title.empty()) {
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+        options->notification_description =
+            android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        if (!options->notification_description.empty()) {
+            // Reset the property
+            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        }
+        MYLOGD("notification (title:  %s, description: %s)\n", options->notification_title.c_str(),
+               options->notification_description.c_str());
+    }
+}
+
+static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
+    MYLOGI("do_zip_file: %d\n", options.do_zip_file);
+    MYLOGI("do_add_date: %d\n", options.do_add_date);
+    MYLOGI("do_vibrate: %d\n", options.do_vibrate);
+    MYLOGI("use_socket: %d\n", options.use_socket);
+    MYLOGI("use_control_socket: %d\n", options.use_control_socket);
+    MYLOGI("do_fb: %d\n", options.do_fb);
+    MYLOGI("do_broadcast: %d\n", options.do_broadcast);
+    MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
+    MYLOGI("show_header_only: %d\n", options.show_header_only);
+    MYLOGI("do_start_service: %d\n", options.do_start_service);
+    MYLOGI("telephony_only: %d\n", options.telephony_only);
+    MYLOGI("wifi_only: %d\n", options.wifi_only);
+    MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
+    MYLOGI("fd: %d\n", options.bugreport_fd.get());
+    MYLOGI("extra_options: %s\n", options.extra_options.c_str());
+    MYLOGI("args: %s\n", options.args.c_str());
+    MYLOGI("notification_title: %s\n", options.notification_title.c_str());
+    MYLOGI("notification_description: %s\n", options.notification_description.c_str());
+}
+
+void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
+                                        const android::base::unique_fd& bugreport_fd_in,
+                                        const android::base::unique_fd& screenshot_fd_in) {
+    // In the new API world, date is always added; output is always a zip file.
+    // TODO(111441001): remove these options once they are obsolete.
+    do_add_date = true;
+    do_zip_file = true;
+
+    // Duplicate the fds because the passed in fds don't outlive the binder transaction.
+    bugreport_fd.reset(dup(bugreport_fd_in.get()));
+    screenshot_fd.reset(dup(screenshot_fd_in.get()));
+
+    extra_options = ModeToString(bugreport_mode);
+    SetOptionsFromMode(bugreport_mode, this);
+}
+
+Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
+    RunStatus status = RunStatus::OK;
+    int c;
+    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
+        switch (c) {
+            // clang-format off
+            case 'd': do_add_date = true;            break;
+            case 'z': do_zip_file = true;            break;
+            // o=use_outfile not supported anymore.
+            // TODO(b/111441001): Remove when all callers have migrated.
+            case 'o': break;
+            case 's': use_socket = true;             break;
+            case 'S': use_control_socket = true;     break;
+            case 'v': show_header_only = true;       break;
+            case 'q': do_vibrate = false;            break;
+            case 'p': do_fb = true;                  break;
+            case 'P': do_progress_updates = true;    break;
+            case 'R': is_remote_mode = true;         break;
+            case 'B': do_broadcast = true;           break;
+            case 'V':                                break;  // compatibility no-op
+            case 'w':
+                // This was already processed
+                break;
+            case 'h':
+                status = RunStatus::HELP;
+                break;
+            default:
+                fprintf(stderr, "Invalid option: %c\n", c);
+                status = RunStatus::INVALID_INPUT;
+                break;
+                // clang-format on
+        }
+    }
+
+    // TODO: use helper function to convert argv into a string
+    for (int i = 0; i < argc; i++) {
+        args += argv[i];
+        if (i < argc - 1) {
+            args += " ";
+        }
+    }
+
+    // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
+    optind = 1;
+
+    SetOptionsFromProperties(this);
+    return status;
+}
+
+bool Dumpstate::DumpOptions::ValidateOptions() const {
+    if (bugreport_fd.get() != -1 && !do_zip_file) {
+        return false;
+    }
+
+    if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
+        return false;
+    }
+
+    if (use_control_socket && !do_zip_file) {
+        return false;
+    }
+
+    if (do_progress_updates && !do_broadcast) {
+        return false;
+    }
+
+    if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
+        return false;
+    }
+    return true;
+}
+
+void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) {
+    options_ = std::move(options);
+}
+
+Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
+    Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
+    if (listener_ != nullptr) {
+        switch (status) {
+            case Dumpstate::RunStatus::OK:
+                listener_->onFinished();
+                break;
+            case Dumpstate::RunStatus::HELP:
+                break;
+            case Dumpstate::RunStatus::INVALID_INPUT:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+                break;
+            case Dumpstate::RunStatus::ERROR:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+                break;
+            case Dumpstate::RunStatus::USER_CONSENT_DENIED:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
+                break;
+            case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+                break;
+        }
+    }
+    return status;
+}
+
+/*
+ * Dumps relevant information to a bugreport based on the given options.
+ *
+ * The bugreport can be dumped to a file or streamed to a socket.
+ *
+ * How dumping to file works:
+ * stdout is redirected to a temporary file. This will later become the main bugreport entry.
+ * stderr is redirected a log file.
+ *
+ * The temporary bugreport is then populated via printfs, dumping contents of files and
+ * output of commands to stdout.
+ *
+ * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
+ * text file.
+ *
+ * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
+ * gets added to the archive.
+ *
+ * Bugreports are first generated in a local directory and later copied to the caller's fd if
+ * supplied.
+ */
+Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
+                                            const std::string& calling_package) {
+    LogDumpOptions(*options_);
+    if (!options_->ValidateOptions()) {
+        MYLOGE("Invalid options specified\n");
+        return RunStatus::INVALID_INPUT;
+    }
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
 
@@ -1856,135 +2514,49 @@
         }
     }
 
-    /* parse arguments */
-    int c;
-    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
-        switch (c) {
-            // clang-format off
-            case 'd': do_add_date = 1;            break;
-            case 'z': do_zip_file = 1;            break;
-            case 'o': use_outfile = optarg;       break;
-            case 's': use_socket = 1;             break;
-            case 'S': use_control_socket = 1;     break;
-            case 'v': show_header_only = true;    break;
-            case 'q': do_vibrate = 0;             break;
-            case 'p': do_fb = 1;                  break;
-            case 'P': ds.update_progress_ = true; break;
-            case 'R': is_remote_mode = 1;         break;
-            case 'B': do_broadcast = 1;           break;
-            case 'V':                             break; // compatibility no-op
-            case 'h':
-                ShowUsageAndExit(0);
-                break;
-            default:
-                fprintf(stderr, "Invalid option: %c\n", c);
-                ShowUsageAndExit();
-                // clang-format on
-        }
+    if (version_ == VERSION_DEFAULT) {
+        version_ = VERSION_CURRENT;
     }
 
-    // TODO: use helper function to convert argv into a string
-    for (int i = 0; i < argc; i++) {
-        ds.args_ += argv[i];
-        if (i < argc - 1) {
-            ds.args_ += " ";
-        }
-    }
-
-    ds.extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    if (!ds.extra_options_.empty()) {
-        // Framework uses a system property to override some command-line args.
-        // Currently, it contains the type of the requested bugreport.
-        if (ds.extra_options_ == "bugreportplus") {
-            // Currently, the dumpstate binder is only used by Shell to update progress.
-            do_start_service = true;
-            ds.update_progress_ = true;
-            do_fb = 0;
-        } else if (ds.extra_options_ == "bugreportremote") {
-            do_vibrate = 0;
-            is_remote_mode = 1;
-            do_fb = 0;
-        } else if (ds.extra_options_ == "bugreportwear") {
-            do_start_service = true;
-            ds.update_progress_ = true;
-            do_zip_file = 1;
-        } else if (ds.extra_options_ == "bugreporttelephony") {
-            telephony_only = true;
-        } else if (ds.extra_options_ == "bugreportwifi") {
-            wifi_only = true;
-            do_zip_file = 1;
-        } else {
-            MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str());
-        }
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    }
-
-    ds.notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
-    if (!ds.notification_title.empty()) {
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
-        ds.notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        if (!ds.notification_description.empty()) {
-            // Reset the property
-            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        }
-        MYLOGD("notification (title:  %s, description: %s)\n",
-               ds.notification_title.c_str(), ds.notification_description.c_str());
-    }
-
-    if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
-        ExitOnInvalidArgs();
-    }
-
-    if (use_control_socket && !do_zip_file) {
-        ExitOnInvalidArgs();
-    }
-
-    if (ds.update_progress_ && !do_broadcast) {
-        ExitOnInvalidArgs();
-    }
-
-    if (is_remote_mode && (ds.update_progress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
-        ExitOnInvalidArgs();
-    }
-
-    if (ds.version_ == VERSION_DEFAULT) {
-        ds.version_ = VERSION_CURRENT;
-    }
-
-    if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) {
+    if (version_ != VERSION_CURRENT && 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_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
                VERSION_SPLIT_ANR.c_str());
-        exit(1);
+        return RunStatus::INVALID_INPUT;
     }
 
-    if (show_header_only) {
-        ds.PrintHeader();
-        exit(0);
+    if (options_->show_header_only) {
+        PrintHeader();
+        return RunStatus::OK;
     }
 
-    /* redirect output if needed */
-    bool is_redirecting = !use_socket && use_outfile;
+    if (options_->bugreport_fd.get() != -1) {
+        // If the output needs to be copied over to the caller's fd, get user consent.
+        android::String16 package(calling_package.c_str());
+        CheckUserConsent(calling_uid, package);
+    }
+
+    // Redirect output if needed
+    bool is_redirecting = options_->OutputToFile();
 
     // TODO: temporarily set progress until it's part of the Dumpstate constructor
     std::string stats_path =
-        is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", dirname(use_outfile))
-                       : "";
-    ds.progress_.reset(new Progress(stats_path));
+        is_redirecting
+            ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
+            : "";
+    progress_.reset(new Progress(stats_path));
 
     /* gets the sequential id */
     uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
-    ds.id_ = ++last_id;
+    id_ = ++last_id;
     android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id));
 
     MYLOGI("begin\n");
 
     register_sig_handler();
 
-    if (do_start_service) {
+    // TODO(b/111441001): maybe skip if already started?
+    if (options_->do_start_service) {
         MYLOGI("Starting 'dumpstate' service\n");
         android::status_t ret;
         if ((ret = android::os::DumpstateService::Start()) != android::OK) {
@@ -1996,91 +2568,48 @@
         MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
     }
 
-    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(),
-           ds.extra_options_.c_str());
+    MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
+           options_->extra_options.c_str());
 
-    MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
+    MYLOGI("bugreport format version: %s\n", version_.c_str());
 
-    ds.do_early_screenshot_ = ds.update_progress_;
+    do_early_screenshot_ = options_->do_progress_updates;
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
-    if (use_socket) {
-        redirect_to_socket(stdout, "dumpstate");
+    if (options_->use_socket) {
+        if (!redirect_to_socket(stdout, "dumpstate")) {
+            return ERROR;
+        }
     }
 
-    if (use_control_socket) {
+    if (options_->use_control_socket) {
         MYLOGD("Opening control socket\n");
-        ds.control_socket_fd_ = open_socket("dumpstate");
-        ds.update_progress_ = 1;
+        control_socket_fd_ = open_socket("dumpstate");
+        if (control_socket_fd_ == -1) {
+            return ERROR;
+        }
+        options_->do_progress_updates = 1;
     }
 
     if (is_redirecting) {
-        ds.bugreport_dir_ = dirname(use_outfile);
-        std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
-        std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
-        ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(use_outfile),
-                                                    device_name.c_str(), build_id.c_str());
-        if (do_add_date) {
-            char date[80];
-            strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
-            ds.name_ = date;
-        } else {
-            ds.name_ = "undated";
-        }
+        PrepareToWriteToFile();
 
-        if (telephony_only) {
-            ds.base_name_ += "-telephony";
-        } else if (wifi_only) {
-            ds.base_name_ += "-wifi";
-        }
-
-        if (do_fb) {
-            ds.screenshot_path_ = ds.GetPath(".png");
-        }
-        ds.tmp_path_ = ds.GetPath(".tmp");
-        ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
-
-        MYLOGD(
-            "Bugreport dir: %s\n"
-            "Base name: %s\n"
-            "Suffix: %s\n"
-            "Log path: %s\n"
-            "Temporary path: %s\n"
-            "Screenshot path: %s\n",
-            ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(),
-            ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
-
-        if (do_zip_file) {
-            ds.path_ = ds.GetPath(".zip");
-            MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
-            create_parent_dirs(ds.path_.c_str());
-            ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
-            if (ds.zip_file == nullptr) {
-                MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
-                do_zip_file = 0;
-            } else {
-                ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
-            }
-            ds.AddTextZipEntry("version.txt", ds.version_);
-        }
-
-        if (ds.update_progress_) {
-            if (do_broadcast) {
+        if (options_->do_progress_updates) {
+            if (options_->do_broadcast) {
                 // clang-format off
-
                 std::vector<std::string> am_args = {
                      "--receiver-permission", "android.permission.DUMP",
-                     "--es", "android.intent.extra.NAME", ds.name_,
-                     "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
-                     "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
-                     "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
+                     "--es", "android.intent.extra.NAME", name_,
+                     "--ei", "android.intent.extra.ID", std::to_string(id_),
+                     "--ei", "android.intent.extra.PID", std::to_string(pid_),
+                     "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
                 };
                 // clang-format on
                 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
             }
-            if (use_control_socket) {
-                dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
+            if (options_->use_control_socket) {
+                dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
             }
         }
     }
@@ -2092,42 +2621,53 @@
         fclose(cmdline);
     }
 
-    if (do_vibrate) {
+    if (options_->do_vibrate) {
         Vibrate(150);
     }
 
-    if (do_fb && ds.do_early_screenshot_) {
-        if (ds.screenshot_path_.empty()) {
+    if (options_->do_fb && do_early_screenshot_) {
+        if (screenshot_path_.empty()) {
             // should not have happened
             MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
         } else {
             MYLOGI("taking early screenshot\n");
-            ds.TakeScreenshot();
+            TakeScreenshot();
         }
     }
 
-    if (do_zip_file) {
-        if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
-            MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
+    if (options_->do_zip_file && zip_file != nullptr) {
+        if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
+            MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
                    strerror(errno));
         }
     }
 
+    int dup_stdout_fd;
+    int dup_stderr_fd;
     if (is_redirecting) {
+        // Redirect stderr to log_path_ for debugging.
         TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
-        redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
-        if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
-            MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
-                   ds.log_path_.c_str(), strerror(errno));
+        if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+            return ERROR;
         }
+        if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+            MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+                   strerror(errno));
+        }
+
+        // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
+        // moved into zip file later, if zipping.
         TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
+        // TODO: why not write to a file instead of stdout to overcome this problem?
         /* TODO: rather than generating a text file now and zipping it later,
            it would be more efficient to redirect stdout to the zip entry
            directly, but the libziparchive doesn't support that option yet. */
-        redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str()));
-        if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+        if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+            return ERROR;
+        }
+        if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
-                   ds.tmp_path_.c_str(), strerror(errno));
+                   tmp_path_.c_str(), strerror(errno));
         }
     }
 
@@ -2137,62 +2677,22 @@
     // NOTE: there should be no stdout output until now, otherwise it would break the header.
     // In particular, DurationReport objects should be created passing 'title, NULL', so their
     // duration is logged into MYLOG instead.
-    ds.PrintHeader();
+    PrintHeader();
 
-    if (telephony_only) {
+    if (options_->telephony_only) {
         DumpstateTelephonyOnly();
-        ds.DumpstateBoard();
-    } else if (wifi_only) {
+        DumpstateBoard();
+    } else if (options_->wifi_only) {
         DumpstateWifiOnly();
     } else {
-        // Dumps systrace right away, otherwise it will be filled with unnecessary events.
-        // First try to dump anrd trace if the daemon is running. Otherwise, dump
-        // the raw trace.
-        if (!dump_anrd_trace()) {
-            dump_systrace();
+        // Dump state for the default case. This also drops root.
+        RunStatus s = DumpstateDefault();
+        if (s != RunStatus::OK) {
+            if (s == RunStatus::USER_CONSENT_TIMED_OUT) {
+                HandleUserConsentDenied();
+            }
+            return s;
         }
-
-        // Invoking the following dumpsys calls before dump_traces() to try and
-        // keep the system stats as close to its initial state as possible.
-        RunDumpsysCritical();
-
-        // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
-        dump_raft();
-
-        /* collect stack traces from Dalvik and native processes (needs root) */
-        dump_traces_path = dump_traces();
-
-        /* Run some operations that require root. */
-        ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
-        ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
-
-        ds.AddDir(RECOVERY_DIR, true);
-        ds.AddDir(RECOVERY_DATA_DIR, true);
-        ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
-        ds.AddDir(LOGPERSIST_DATA_DIR, false);
-        if (!PropertiesHelper::IsUserBuild()) {
-            ds.AddDir(PROFILE_DATA_DIR_CUR, true);
-            ds.AddDir(PROFILE_DATA_DIR_REF, true);
-        }
-        add_mountinfo();
-        DumpIpTablesAsRoot();
-
-        // Capture any IPSec policies in play.  No keys are exposed here.
-        RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
-                   CommandOptions::WithTimeout(10).Build());
-
-        // Run ss as root so we can see socket marks.
-        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;
-        }
-
-        dumpstate();
     }
 
     /* close output if needed */
@@ -2200,80 +2700,48 @@
         TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
     }
 
-    /* rename or zip the (now complete) .tmp file to its final location */
-    if (use_outfile) {
+    // Rename, and/or zip the (now complete) .tmp file within the internal directory.
+    if (options_->OutputToFile()) {
+        FinalizeFile();
+    }
 
-        /* check if user changed the suffix using system properties */
-        std::string name = android::base::GetProperty(
-            android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
-        bool change_suffix= false;
-        if (!name.empty()) {
-            /* must whitelist which characters are allowed, otherwise it could cross directories */
-            std::regex valid_regex("^[-_a-zA-Z0-9]+$");
-            if (std::regex_match(name.c_str(), valid_regex)) {
-                change_suffix = true;
+    // Share the final file with the caller if the user has consented.
+    Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
+    if (options_->bugreport_fd.get() != -1) {
+        status = CopyBugreportIfUserConsented();
+        if (status != Dumpstate::RunStatus::OK &&
+            status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+            // Do an early return if there were errors. We make an exception for consent
+            // timing out because it's possible the user got distracted. In this case the
+            // bugreport is not shared but made available for manual retrieval.
+            MYLOGI("User denied consent. Returning\n");
+            return status;
+        }
+        if (options_->do_fb && options_->screenshot_fd.get() != -1) {
+            bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
+                                                            options_->screenshot_fd.get());
+            if (copy_succeeded) {
+                android::os::UnlinkAndLogOnError(screenshot_path_);
+            }
+        }
+        if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+            MYLOGI(
+                "Did not receive user consent yet."
+                " Will not copy the bugreport artifacts to caller.\n");
+            const String16 incidentcompanion("incidentcompanion");
+            sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+            if (ics != nullptr) {
+                MYLOGD("Canceling user consent request via incidentcompanion service\n");
+                android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization(
+                        consent_callback_.get());
             } else {
-                MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
-            }
-        }
-        if (change_suffix) {
-            MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
-            ds.name_ = name;
-            if (!ds.screenshot_path_.empty()) {
-                std::string new_screenshot_path = ds.GetPath(".png");
-                if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
-                    MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
-                           new_screenshot_path.c_str(), strerror(errno));
-                } else {
-                    ds.screenshot_path_ = new_screenshot_path;
-                }
-            }
-        }
-
-        bool do_text_file = true;
-        if (do_zip_file) {
-            if (!ds.FinishZipFile()) {
-                MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
-                do_text_file = true;
-            } else {
-                do_text_file = false;
-                // Since zip file is already created, it needs to be renamed.
-                std::string new_path = ds.GetPath(".zip");
-                if (ds.path_ != new_path) {
-                    MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
-                    if (rename(ds.path_.c_str(), new_path.c_str())) {
-                        MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
-                               strerror(errno));
-                    } else {
-                        ds.path_ = new_path;
-                    }
-                }
-            }
-        }
-        if (do_text_file) {
-            ds.path_ = ds.GetPath(".txt");
-            MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(),
-                   ds.tmp_path_.c_str());
-            if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
-                MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(),
-                       strerror(errno));
-                ds.path_.clear();
-            }
-        }
-        if (use_control_socket) {
-            if (do_text_file) {
-                dprintf(ds.control_socket_fd_,
-                        "FAIL:could not create zip file, check %s "
-                        "for more details\n",
-                        ds.log_path_.c_str());
-            } else {
-                dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str());
+                MYLOGD("Unable to cancel user consent; incidentcompanion service unavailable\n");
             }
         }
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
-    if (do_vibrate) {
+    if (options_->do_vibrate) {
         for (int i = 0; i < 3; i++) {
             Vibrate(75);
             usleep((75 + 50) * 1000);
@@ -2281,65 +2749,138 @@
     }
 
     /* tell activity manager we're done */
-    if (do_broadcast) {
-        if (!ds.path_.empty()) {
-            MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
-            // clang-format off
-
-            std::vector<std::string> am_args = {
-                 "--receiver-permission", "android.permission.DUMP",
-                 "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
-                 "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
-                 "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
-                 "--es", "android.intent.extra.BUGREPORT", ds.path_,
-                 "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
-            };
-            // clang-format on
-            if (do_fb) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.SCREENSHOT");
-                am_args.push_back(ds.screenshot_path_);
-            }
-            if (!ds.notification_title.empty()) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.TITLE");
-                am_args.push_back(ds.notification_title);
-                if (!ds.notification_description.empty()) {
-                    am_args.push_back("--es");
-                    am_args.push_back("android.intent.extra.DESCRIPTION");
-                    am_args.push_back(ds.notification_description);
-                }
-            }
-            if (is_remote_mode) {
-                am_args.push_back("--es");
-                am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
-                am_args.push_back(SHA256_file_hash(ds.path_));
-                SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED",
-                              am_args);
-            } else {
-                SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
-            }
-        } else {
-            MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
-        }
+    if (options_->do_broadcast) {
+        SendBugreportFinishedBroadcast();
+        // Note that listener_ is notified in Run();
     }
 
-    MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(),
-           ds.progress_->GetInitialMax());
-    ds.progress_->Save();
-    MYLOGI("done (id %d)\n", ds.id_);
+    MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
+           progress_->GetInitialMax());
+    progress_->Save();
+    MYLOGI("done (id %d)\n", id_);
 
     if (is_redirecting) {
         TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
     }
 
-    if (use_control_socket && ds.control_socket_fd_ != -1) {
+    if (options_->use_control_socket && control_socket_fd_ != -1) {
         MYLOGD("Closing control socket\n");
-        close(ds.control_socket_fd_);
+        close(control_socket_fd_);
     }
 
-    ds.tombstone_data_.clear();
-    ds.anr_data_.clear();
+    tombstone_data_.clear();
+    anr_data_.clear();
 
-    return 0;
+    return (consent_callback_ != nullptr &&
+            consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
+               ? USER_CONSENT_TIMED_OUT
+               : RunStatus::OK;
+}
+
+void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
+    consent_callback_ = new ConsentCallback();
+    const String16 incidentcompanion("incidentcompanion");
+    sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+    if (ics != nullptr) {
+        MYLOGD("Checking user consent via incidentcompanion service\n");
+        android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
+            calling_uid, calling_package, String16(), String16(),
+            0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
+    } else {
+        MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
+    }
+}
+
+bool Dumpstate::IsUserConsentDenied() const {
+    return ds.consent_callback_ != nullptr &&
+           ds.consent_callback_->getResult() == UserConsentResult::DENIED;
+}
+
+void Dumpstate::CleanupFiles() {
+    android::os::UnlinkAndLogOnError(tmp_path_);
+    android::os::UnlinkAndLogOnError(screenshot_path_);
+    android::os::UnlinkAndLogOnError(path_);
+}
+
+Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
+    MYLOGD("User denied consent; deleting files and returning\n");
+    CleanupFiles();
+    return USER_CONSENT_DENIED;
+}
+
+Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
+    // If the caller has asked to copy the bugreport over to their directory, we need explicit
+    // user consent.
+    UserConsentResult consent_result = consent_callback_->getResult();
+    if (consent_result == UserConsentResult::UNAVAILABLE) {
+        // User has not responded yet.
+        uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
+        if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
+            uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
+            MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
+            sleep(delay_seconds);
+        }
+        consent_result = consent_callback_->getResult();
+    }
+    if (consent_result == UserConsentResult::DENIED) {
+        // User has explicitly denied sharing with the app. To be safe delete the
+        // internal bugreport & tmp files.
+        return HandleUserConsentDenied();
+    }
+    if (consent_result == UserConsentResult::APPROVED) {
+        bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
+        if (copy_succeeded) {
+            android::os::UnlinkAndLogOnError(path_);
+        }
+        return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
+    } else if (consent_result == UserConsentResult::UNAVAILABLE) {
+        // consent_result is still UNAVAILABLE. The user has likely not responded yet.
+        // Since we do not have user consent to share the bugreport it does not get
+        // copied over to the calling app but remains in the internal directory from
+        // where the user can manually pull it.
+        return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
+    }
+    // Unknown result; must be a programming error.
+    MYLOGE("Unknown user consent result:%d\n", consent_result);
+    return Dumpstate::RunStatus::ERROR;
+}
+
+Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
+    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+    Dumpstate::RunStatus status = options->Initialize(argc, argv);
+    if (status == Dumpstate::RunStatus::OK) {
+        SetOptions(std::move(options));
+        // When directly running dumpstate binary, the output is not expected to be written
+        // to any external file descriptor.
+        assert(options_->bugreport_fd.get() == -1);
+
+        // calling_uid and calling_package are for user consent to share the bugreport with
+        // an app; they are irrelvant here because bugreport is only written to a local
+        // directory, and not shared.
+        status = Run(-1 /* calling_uid */, "" /* calling_package */);
+    }
+    return status;
+}
+
+/* Main entry point for dumpstate binary. */
+int run_main(int argc, char* argv[]) {
+    Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
+
+    switch (status) {
+        case Dumpstate::RunStatus::OK:
+            exit(0);
+        case Dumpstate::RunStatus::HELP:
+            ShowUsage();
+            exit(0);
+        case Dumpstate::RunStatus::INVALID_INPUT:
+            fprintf(stderr, "Invalid combination of args\n");
+            ShowUsage();
+            exit(1);
+        case Dumpstate::RunStatus::ERROR:
+            FALLTHROUGH_INTENDED;
+        case Dumpstate::RunStatus::USER_CONSENT_DENIED:
+            FALLTHROUGH_INTENDED;
+        case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
+            exit(2);
+    }
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index b220013..d02ec75 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,8 @@
 
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
+#include <android/os/BnIncidentAuthListener.h>
+#include <android/os/IDumpstate.h>
 #include <android/os/IDumpstateListener.h>
 #include <utils/StrongPointer.h>
 #include <ziparchive/zip_writer.h>
@@ -42,6 +44,9 @@
 // TODO: and then remove explicitly android::os::dumpstate:: prefixes
 namespace android {
 namespace os {
+
+struct DumpstateOptions;
+
 namespace dumpstate {
 
 class DumpstateTest;
@@ -68,13 +73,13 @@
  */
 class DurationReporter {
   public:
-    DurationReporter(const std::string& title, bool log_only = false);
+    explicit DurationReporter(const std::string& title, bool logcat_only = false);
 
     ~DurationReporter();
 
   private:
     std::string title_;
-    bool log_only_;
+    bool logcat_only_;
     uint64_t started_;
 
     DISALLOW_COPY_AND_ASSIGN(DurationReporter);
@@ -107,7 +112,7 @@
      */
     static const int kDefaultMax;
 
-    Progress(const std::string& path = "");
+    explicit Progress(const std::string& path = "");
 
     // Gets the current progress.
     int32_t Get() const;
@@ -138,7 +143,7 @@
     float growth_factor_;
     int32_t n_runs_;
     int32_t average_max_;
-    const std::string& path_;
+    std::string path_;
 };
 
 /*
@@ -160,6 +165,11 @@
 static std::string VERSION_DEFAULT = "default";
 
 /*
+ * Directory used by Dumpstate binary to keep its local files.
+ */
+static const std::string DUMPSTATE_DIRECTORY = "/bugreports";
+
+/*
  * Structure that contains the information of an open dump file.
  */
 struct DumpData {
@@ -183,6 +193,19 @@
     friend class DumpstateTest;
 
   public:
+    enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT };
+
+    // The mode under which the bugreport should be run. Each mode encapsulates a few options.
+    enum BugreportMode {
+        BUGREPORT_FULL = android::os::IDumpstate::BUGREPORT_MODE_FULL,
+        BUGREPORT_INTERACTIVE = android::os::IDumpstate::BUGREPORT_MODE_INTERACTIVE,
+        BUGREPORT_REMOTE = android::os::IDumpstate::BUGREPORT_MODE_REMOTE,
+        BUGREPORT_WEAR = android::os::IDumpstate::BUGREPORT_MODE_WEAR,
+        BUGREPORT_TELEPHONY = android::os::IDumpstate::BUGREPORT_MODE_TELEPHONY,
+        BUGREPORT_WIFI = android::os::IDumpstate::BUGREPORT_MODE_WIFI,
+        BUGREPORT_DEFAULT = android::os::IDumpstate::BUGREPORT_MODE_DEFAULT
+    };
+
     static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
 
     static Dumpstate& GetInstance();
@@ -245,7 +268,7 @@
                                         std::chrono::milliseconds timeout);
 
     /*
-     * Adds a text entry entry to the existing zip file.
+     * Adds a text entry to the existing zip file.
      */
     bool AddTextZipEntry(const std::string& entry_name, const std::string& content);
 
@@ -268,6 +291,12 @@
     // TODO: temporary method until Dumpstate object is properly set
     void SetProgress(std::unique_ptr<Progress> progress);
 
+    // Dumps Dalvik and native stack traces, sets the trace file location to path
+    // if it succeeded.
+    // Note that it returns early if user consent is denied with status USER_CONSENT_DENIED.
+    // Returns OK in all other cases.
+    RunStatus DumpTraces(const char** path);
+
     void DumpstateBoard();
 
     /*
@@ -284,22 +313,92 @@
      */
     bool FinishZipFile();
 
-    /* Gets the path of a bugreport file with the given suffix. */
+    /* Constructs a full path inside directory with file name formatted using the given suffix. */
+    std::string GetPath(const std::string& directory, const std::string& suffix) const;
+
+    /* Constructs a full path inside bugreport_internal_dir_ with file name formatted using 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
+    struct DumpOptions;
 
+    /* Main entry point for running a complete bugreport. */
+    RunStatus Run(int32_t calling_uid, const std::string& calling_package);
+
+    RunStatus ParseCommandlineAndRun(int argc, char* argv[]);
+
+    /* Sets runtime options. */
+    void SetOptions(std::unique_ptr<DumpOptions> options);
+
+    /*
+     * Returns true if user consent is necessary and has been denied.
+     * Consent is only necessary if the caller has asked to copy over the bugreport to a file they
+     * provided.
+     */
+    bool IsUserConsentDenied() const;
+
+    /*
+     * Structure to hold options that determine the behavior of dumpstate.
+     */
+    struct DumpOptions {
+        bool do_add_date = false;
+        bool do_zip_file = false;
+        bool do_vibrate = true;
+        // Writes bugreport content to a socket; only flatfile format is supported.
+        bool use_socket = false;
+        bool use_control_socket = false;
+        bool do_fb = false;
+        bool do_broadcast = false;
+        bool is_remote_mode = false;
+        bool show_header_only = false;
+        bool do_start_service = false;
+        bool telephony_only = false;
+        bool wifi_only = false;
+        // Whether progress updates should be published.
+        bool do_progress_updates = false;
+        // File descriptor to output zip file.
+        android::base::unique_fd bugreport_fd;
+        // File descriptor to screenshot file.
+        android::base::unique_fd screenshot_fd;
+        // TODO: rename to MODE.
+        // Extra options passed as system property.
+        std::string extra_options;
+        // Command-line arguments as string
+        std::string args;
+        // Notification title and description
+        std::string notification_title;
+        std::string notification_description;
+
+        /* Initializes options from commandline arguments and system properties. */
+        RunStatus Initialize(int argc, char* argv[]);
+
+        /* Initializes options from the requested mode. */
+        void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd,
+                        const android::base::unique_fd& screenshot_fd);
+
+        /* Returns true if the options set so far are consistent. */
+        bool ValidateOptions() const;
+
+        /* Returns if options specified require writing bugreport to a file */
+        bool OutputToFile() const {
+            // If we are not writing to socket, we will write to a file. If bugreport_fd is
+            // specified, it is preferred. If not bugreport is written to /bugreports.
+            return !use_socket;
+        }
+    };
+
+    // TODO: initialize fields on constructor
     // dumpstate id - unique after each device reboot.
     uint32_t id_;
 
     // dumpstate pid
     pid_t pid_;
 
-    // Whether progress updates should be published.
-    bool update_progress_ = false;
+    // Runtime options.
+    std::unique_ptr<DumpOptions> options_;
 
     // How frequently the progess should be updated;the listener will only be notificated when the
     // delta from the previous update is more than the threshold.
@@ -319,18 +418,6 @@
     // Bugreport format version;
     std::string version_ = VERSION_CURRENT;
 
-    // Command-line arguments as string
-    std::string args_;
-
-    // Extra options passed as system property.
-    std::string extra_options_;
-
-    // Full path of the directory where the bugreport files will be written.
-    std::string bugreport_dir_;
-
-    // Full path of the temporary file containing the screenshot (when requested).
-    std::string screenshot_path_;
-
     time_t now_;
 
     // Base name (without suffix or extensions) of the bugreport files, typically
@@ -341,15 +428,23 @@
     // `-d`), but it could be changed by the user..
     std::string name_;
 
-    // Full path of the temporary file containing the bugreport.
+    std::string bugreport_internal_dir_ = DUMPSTATE_DIRECTORY;
+
+    // Full path of the temporary file containing the bugreport, inside bugreport_internal_dir_.
+    // At the very end this file is pulled into the zip file.
     std::string tmp_path_;
 
-    // Full path of the file containing the dumpstate logs.
+    // Full path of the file containing the dumpstate logs, inside bugreport_internal_dir_.
+    // This is useful for debugging.
     std::string log_path_;
 
-    // Pointer to the actual path, be it zip or text.
+    // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
     std::string path_;
 
+    // TODO: If temporary this should be removed at the end.
+    // Full path of the temporary file containing the screenshot (when requested).
+    std::string screenshot_path_;
+
     // Pointer to the zipped file.
     std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
 
@@ -361,19 +456,52 @@
     std::string listener_name_;
     bool report_section_;
 
-    // Notification title and description
-    std::string notification_title;
-    std::string notification_description;
-
     // List of open tombstone dump files.
     std::vector<DumpData> tombstone_data_;
 
     // List of open ANR dump files.
     std::vector<DumpData> anr_data_;
 
+    // A callback to IncidentCompanion service, which checks user consent for sharing the
+    // bugreport with the calling app. If the user has not responded yet to the dialog it will
+    // be neither confirmed nor denied.
+    class ConsentCallback : public android::os::BnIncidentAuthListener {
+      public:
+        ConsentCallback();
+        android::binder::Status onReportApproved() override;
+        android::binder::Status onReportDenied() override;
+
+        enum ConsentResult { APPROVED, DENIED, UNAVAILABLE };
+
+        ConsentResult getResult();
+
+        // Returns the time since creating this listener
+        uint64_t getElapsedTimeMs() const;
+
+      private:
+        ConsentResult result_;
+        uint64_t start_time_;
+        std::mutex lock_;
+    };
+
   private:
+    RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package);
+
+    void CheckUserConsent(int32_t calling_uid, const android::String16& calling_package);
+
+    // Removes the in progress files output files (tmp file, zip/txt file, screenshot),
+    // but leaves the log file alone.
+    void CleanupFiles();
+
+    RunStatus HandleUserConsentDenied();
+
+    // Copies bugreport artifacts over to the caller's directories provided there is user consent.
+    RunStatus CopyBugreportIfUserConsented();
+
     // Used by GetInstance() only.
-    Dumpstate(const std::string& version = VERSION_CURRENT);
+    explicit Dumpstate(const std::string& version = VERSION_CURRENT);
+
+    android::sp<ConsentCallback> consent_callback_;
 
     DISALLOW_COPY_AND_ASSIGN(Dumpstate);
 };
@@ -404,21 +532,30 @@
 /** opens a socket and returns its file descriptor */
 int open_socket(const char *service);
 
-/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service);
+/*
+ * Redirects 'redirect' to a service control socket.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_socket(FILE* redirect, const char* service);
 
-/* redirect output to a new file */
-void redirect_to_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to a file indicated by 'path', truncating it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_file(FILE* redirect, char* path);
 
-/* redirect output to an existing file */
-void redirect_to_existing_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to an existing file indicated by 'path', appending it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_existing_file(FILE* redirect, char* path);
 
 /* create leading directories, if necessary */
 void create_parent_dirs(const char *path);
 
-/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
-const char *dump_traces();
-
 /* for each process in the system, run the specified function */
 void for_each_pid(for_each_pid_func func, const char *header);
 
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 2e72574..14937b8 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -17,3 +17,9 @@
     class main
     disabled
     oneshot
+
+# bugreportd starts dumpstate binder service and makes it wait for a listener to connect.
+service bugreportd /system/bin/dumpstate -w
+    class main
+    disabled
+    oneshot
diff --git a/cmds/dumpstate/main.cpp b/cmds/dumpstate/main.cpp
index 78aad11..68d3733 100644
--- a/cmds/dumpstate/main.cpp
+++ b/cmds/dumpstate/main.cpp
@@ -14,8 +14,55 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "dumpstate"
+
+#include <binder/IPCThreadState.h>
+
+#include "DumpstateInternal.h"
+#include "DumpstateService.h"
 #include "dumpstate.h"
 
+namespace {
+
+// Returns true if we should start the service and wait for a listener
+// to bind with bugreport options.
+bool ShouldStartServiceAndWait(int argc, char* argv[]) {
+    bool do_wait = false;
+    int c;
+    // Keep flags in sync with Dumpstate::DumpOptions::Initialize.
+    while ((c = getopt(argc, argv, "wdho:svqzpPBRSV:")) != -1 && !do_wait) {
+        switch (c) {
+            case 'w':
+                do_wait = true;
+                break;
+            default:
+                // Ignore all other options
+                break;
+        }
+    }
+
+    // Reset next index used by getopt so getopt can be called called again in Dumpstate::Run to
+    // parse bugreport options.
+    optind = 1;
+    return do_wait;
+}
+
+}  // namespace
+
 int main(int argc, char* argv[]) {
-    return run_main(argc, argv);
+    if (ShouldStartServiceAndWait(argc, argv)) {
+        int ret;
+        if ((ret = android::os::DumpstateService::Start()) != android::OK) {
+            MYLOGE("Unable to start 'dumpstate' service: %d", ret);
+            exit(1);
+        }
+        MYLOGI("'dumpstate' service started and will wait for a call to startBugreport()");
+
+        // Waits forever for an incoming connection.
+        // TODO(b/111441001): should this time out?
+        android::IPCThreadState::self()->joinThreadPool();
+        return 0;
+    } else {
+        return run_main(argc, argv);
+    }
 }
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 61a5ef5..fc3642c 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -21,6 +21,10 @@
 #include <libgen.h>
 
 #include <android-base/file.h>
+#include <android/os/BnDumpstate.h>
+#include <android/os/BnDumpstateListener.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <ziparchive/zip_archive.h>
 
@@ -34,6 +38,24 @@
 
 using ::testing::Test;
 using ::std::literals::chrono_literals::operator""s;
+using android::base::unique_fd;
+
+class DumpstateListener;
+
+namespace {
+
+sp<IDumpstate> GetDumpstateService() {
+    return android::interface_cast<IDumpstate>(
+        android::defaultServiceManager()->getService(String16("dumpstate")));
+}
+
+int OpenForWrite(const std::string& filename) {
+    return TEMP_FAILURE_RETRY(open(filename.c_str(),
+                                   O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+}
+
+}  // namespace
 
 struct SectionInfo {
     std::string name;
@@ -46,29 +68,71 @@
  * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
  * section details generated by dumpstate are added to a vector to be used by Tests later.
  */
-class DumpstateListener : public IDumpstateListener {
+class DumpstateListener : public BnDumpstateListener {
   public:
-    int outFd_, max_progress_;
-    std::shared_ptr<std::vector<SectionInfo>> sections_;
     DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
-        : outFd_(fd), max_progress_(5000), sections_(sections) {
+        : out_fd_(fd), sections_(sections) {
     }
-    binder::Status onProgressUpdated(int32_t progress) override {
-        dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
+
+    DumpstateListener(int fd) : out_fd_(fd) {
+    }
+
+    binder::Status onProgress(int32_t progress) override {
+        dprintf(out_fd_, "\rIn progress %d", progress);
         return binder::Status::ok();
     }
+
+    binder::Status onError(int32_t error_code) override {
+        std::lock_guard<std::mutex> lock(lock_);
+        error_code_ = error_code;
+        dprintf(out_fd_, "\rError code %d", error_code);
+        return binder::Status::ok();
+    }
+
+    binder::Status onFinished() override {
+        std::lock_guard<std::mutex> lock(lock_);
+        is_finished_ = true;
+        dprintf(out_fd_, "\rFinished");
+        return binder::Status::ok();
+    }
+
+    binder::Status onProgressUpdated(int32_t progress) override {
+        dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
+        return binder::Status::ok();
+    }
+
     binder::Status onMaxProgressUpdated(int32_t max_progress) override {
+        std::lock_guard<std::mutex> lock(lock_);
         max_progress_ = max_progress;
         return binder::Status::ok();
     }
+
     binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
                                      int32_t duration_ms) override {
-        sections_->push_back({name, status, size_bytes, duration_ms});
+        std::lock_guard<std::mutex> lock(lock_);
+        if (sections_.get() != nullptr) {
+            sections_->push_back({name, status, size_bytes, duration_ms});
+        }
         return binder::Status::ok();
     }
-    IBinder* onAsBinder() override {
-        return nullptr;
+
+    bool getIsFinished() {
+        std::lock_guard<std::mutex> lock(lock_);
+        return is_finished_;
     }
+
+    int getErrorCode() {
+        std::lock_guard<std::mutex> lock(lock_);
+        return error_code_;
+    }
+
+  private:
+    int out_fd_;
+    int max_progress_ = 5000;
+    int error_code_ = -1;
+    bool is_finished_ = false;
+    std::shared_ptr<std::vector<SectionInfo>> sections_;
+    std::mutex lock_;
 };
 
 /**
@@ -97,7 +161,7 @@
         ds.listener_name_ = "Smokey";
         ds.report_section_ = true;
         auto start = std::chrono::steady_clock::now();
-        run_main(ARRAY_SIZE(argv), argv);
+        ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
         auto end = std::chrono::steady_clock::now();
         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
     }
@@ -281,6 +345,148 @@
     SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
 }
 
+class DumpstateBinderTest : public Test {
+  protected:
+    void SetUp() override {
+        // In case there is a stray service, stop it first.
+        property_set("ctl.stop", "bugreportd");
+        // dry_run results in a faster bugreport.
+        property_set("dumpstate.dry_run", "true");
+        // We need to receive some async calls later. Ensure we have binder threads.
+        ProcessState::self()->startThreadPool();
+    }
+
+    void TearDown() override {
+        property_set("ctl.stop", "bugreportd");
+        property_set("dumpstate.dry_run", "");
+
+        unlink("/data/local/tmp/tmp.zip");
+        unlink("/data/local/tmp/tmp.png");
+    }
+
+    // Waits until listener gets the callbacks.
+    void WaitTillExecutionComplete(DumpstateListener* listener) {
+        // Wait till one of finished, error or timeout.
+        static const int kBugreportTimeoutSeconds = 120;
+        int i = 0;
+        while (!listener->getIsFinished() && listener->getErrorCode() == -1 &&
+               i < kBugreportTimeoutSeconds) {
+            sleep(1);
+            i++;
+        }
+    }
+};
+
+TEST_F(DumpstateBinderTest, Baseline) {
+    // In the beginning dumpstate binder service is not running.
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_EQ(ds_binder, nullptr);
+
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("dumpstate.dry_run", "true");
+    property_set("ctl.start", "bugreportd");
+
+    // Now we are able to retrieve dumpstate binder service.
+    ds_binder = GetDumpstateService();
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/bugreports/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/bugreports/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
+    // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
+    // gets expected callbacks.
+    EXPECT_TRUE(status.isOk());
+    WaitTillExecutionComplete(listener.get());
+
+    // Bugreport generation requires user consent, which we cannot get in a test set up,
+    // so instead of getting is_finished_, we are more likely to get a consent error.
+    EXPECT_TRUE(
+        listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+        listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+
+    // The service should have died on its own, freeing itself up for a new invocation.
+    sleep(2);
+    ds_binder = GetDumpstateService();
+    EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) {
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("ctl.start", "bugreportd");
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    // Call startBugreport with bad arguments.
+    sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  2000,  // invalid bugreport mode
+                                  listener);
+    EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+
+    // The service should have died, freeing itself up for a new invocation.
+    sleep(2);
+    ds_binder = GetDumpstateService();
+    EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) {
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("dumpstate.dry_run", "true");
+    property_set("ctl.start", "bugreportd");
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
+    EXPECT_TRUE(status.isOk());
+
+    // try to make another call to startBugreport. This should fail.
+    sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
+    status = ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                       Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
+    EXPECT_FALSE(status.isOk());
+    WaitTillExecutionComplete(listener2.get());
+    EXPECT_EQ(listener2->getErrorCode(),
+              IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
+
+    // Meanwhile the first call works as expected. Service should not die in this case.
+    WaitTillExecutionComplete(listener1.get());
+
+    // Bugreport generation requires user consent, which we cannot get in a test set up,
+    // so instead of getting is_finished_, we are more likely to get a consent error.
+    EXPECT_TRUE(
+        listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+        listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+}
+
 }  // namespace dumpstate
 }  // namespace os
 }  // namespace android
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 838b385..71d15f4 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -36,6 +36,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <cutils/properties.h>
 
 namespace android {
 namespace os {
@@ -54,8 +55,13 @@
 using ::testing::internal::GetCapturedStderr;
 using ::testing::internal::GetCapturedStdout;
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
 class DumpstateListenerMock : public IDumpstateListener {
   public:
+    MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
+    MOCK_METHOD1(onError, binder::Status(int32_t error_code));
+    MOCK_METHOD0(onFinished, binder::Status());
     MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
     MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
     MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
@@ -83,6 +89,10 @@
         PropertiesHelper::build_type_ = build_type;
     }
 
+    void SetUnroot(bool unroot) const {
+        PropertiesHelper::unroot_ = unroot;
+    }
+
     bool IsStandalone() const {
         return calls_ == 1;
     }
@@ -135,6 +145,445 @@
     }
 };
 
+class DumpOptionsTest : public Test {
+  public:
+    virtual ~DumpOptionsTest() {
+    }
+    virtual void SetUp() {
+        options_ = Dumpstate::DumpOptions();
+    }
+    void TearDown() {
+        // Reset the property
+        property_set("dumpstate.options", "");
+    }
+    Dumpstate::DumpOptions options_;
+};
+
+TEST_F(DumpOptionsTest, InitializeNone) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate")
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+
+    EXPECT_FALSE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_zip_file);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstatez"),
+        const_cast<char*>("-S"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.use_control_socket);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-s"),
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.use_socket);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_zip_file);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializeFullBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+    property_set("dumpstate.options", "bugreportfull");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_fb);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_broadcast);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.do_start_service);
+}
+
+TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportplus");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_TRUE(options_.do_start_service);
+    EXPECT_FALSE(options_.do_fb);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportremote");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_fb);
+
+    // Other options retain default values
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeWearBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportwear");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_fb);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_TRUE(options_.do_start_service);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreporttelephony");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.telephony_only);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "bugreportwifi");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_TRUE(options_.do_broadcast);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.wifi_only);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
+    // default: commandline options are not overridden
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("bugreport"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-B"),
+        const_cast<char*>("-z"),
+    };
+    // clang-format on
+
+    property_set("dumpstate.options", "");
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_fb);
+    EXPECT_TRUE(options_.do_zip_file);
+    EXPECT_TRUE(options_.do_broadcast);
+
+    // Other options retain default values
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.wifi_only);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial1) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-d"),
+        const_cast<char*>("-z"),
+        const_cast<char*>("-s"),
+        const_cast<char*>("-S"),
+
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.do_add_date);
+    EXPECT_TRUE(options_.do_zip_file);
+    // TODO: Maybe we should trim the filename
+    EXPECT_TRUE(options_.use_socket);
+    EXPECT_TRUE(options_.use_control_socket);
+
+    // Other options retain default values
+    EXPECT_FALSE(options_.show_header_only);
+    EXPECT_TRUE(options_.do_vibrate);
+    EXPECT_FALSE(options_.do_fb);
+    EXPECT_FALSE(options_.do_progress_updates);
+    EXPECT_FALSE(options_.is_remote_mode);
+    EXPECT_FALSE(options_.do_broadcast);
+}
+
+TEST_F(DumpOptionsTest, InitializePartial2) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-v"),
+        const_cast<char*>("-q"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-P"),
+        const_cast<char*>("-R"),
+        const_cast<char*>("-B"),
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+    EXPECT_TRUE(options_.show_header_only);
+    EXPECT_FALSE(options_.do_vibrate);
+    EXPECT_TRUE(options_.do_fb);
+    EXPECT_TRUE(options_.do_progress_updates);
+    EXPECT_TRUE(options_.is_remote_mode);
+    EXPECT_TRUE(options_.do_broadcast);
+
+    // Other options retain default values
+    EXPECT_FALSE(options_.do_add_date);
+    EXPECT_FALSE(options_.do_zip_file);
+    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.use_control_socket);
+}
+
+TEST_F(DumpOptionsTest, InitializeHelp) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-h")
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    // -h is for help.
+    EXPECT_EQ(status, Dumpstate::RunStatus::HELP);
+}
+
+TEST_F(DumpOptionsTest, InitializeUnknown) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-u")  // unknown flag
+    };
+    // clang-format on
+
+    Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
+
+    // -u is unknown.
+    EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
+    options_.do_zip_file = true;
+    // Writing to socket = !writing to file.
+    options_.use_socket = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.use_socket = false;
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+    options_.do_broadcast = true;
+    // Writing to socket = !writing to file.
+    options_.use_socket = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.use_socket = false;
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
+    options_.use_control_socket = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.do_zip_file = true;
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
+    options_.do_progress_updates = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.do_broadcast = true;
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
+TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+    options_.is_remote_mode = true;
+    EXPECT_FALSE(options_.ValidateOptions());
+
+    options_.do_broadcast = true;
+    options_.do_zip_file = true;
+    options_.do_add_date = true;
+    EXPECT_TRUE(options_.ValidateOptions());
+}
+
 class DumpstateTest : public DumpstateBaseTest {
   public:
     void SetUp() {
@@ -142,8 +591,8 @@
         SetDryRun(false);
         SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
         ds.progress_.reset(new Progress());
-        ds.update_progress_ = false;
         ds.update_progress_threshold_ = 0;
+        ds.options_.reset(new Dumpstate::DumpOptions());
     }
 
     // Runs a command and capture `stdout` and `stderr`.
@@ -168,7 +617,7 @@
     }
 
     void SetProgress(long progress, long initial_max, long threshold = 0) {
-        ds.update_progress_ = true;
+        ds.options_->do_progress_updates = true;
         ds.update_progress_threshold_ = threshold;
         ds.last_updated_progress_ = 0;
         ds.progress_.reset(new Progress(initial_max, progress, 1.2));
@@ -188,8 +637,9 @@
         }
 
         if (update_progress) {
-            message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
-                                                   listener_name.c_str(), progress, max);
+            message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
+                                                   listener_name.c_str(), progress, max,
+                                                   (100 * progress / max));
         }
 
         return message;
@@ -216,8 +666,7 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
     // We don't know the exact duration, so we check the prefix and suffix
     EXPECT_THAT(out,
-                StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n------"));
-    EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
+                StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n"));
 }
 
 TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
@@ -252,8 +701,7 @@
     EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
     // We don't know the exact duration, so we check the prefix and suffix
     EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand +
-                                ") ------\n\t(skipped on dry run)\n------"));
-    EXPECT_THAT(out, EndsWith("s was the duration of 'I AM GROOT' ------\n"));
+                                ") ------\n\t(skipped on dry run)\n"));
     EXPECT_THAT(err, IsEmpty());
 }
 
@@ -348,12 +796,14 @@
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgressUpdated(20));
+    EXPECT_CALL(*listener, onProgress(66));  // 20/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
     std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
     EXPECT_CALL(*listener, onProgressUpdated(30));
+    EXPECT_CALL(*listener, onProgress(100));  // 35/35 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -362,6 +812,7 @@
     // Run a command that will increase maximum timeout.
     EXPECT_CALL(*listener, onProgressUpdated(31));
     EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+    EXPECT_CALL(*listener, onProgress(83));  // 31/37 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30);  // 20% increase
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -370,6 +821,7 @@
     // Make sure command ran while in dry_run is counted.
     SetDryRun(true);
     EXPECT_CALL(*listener, onProgressUpdated(35));
+    EXPECT_CALL(*listener, onProgress(94));  // 35/37 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
     EXPECT_THAT(out, IsEmpty());
@@ -386,6 +838,7 @@
 
     // First update should always be sent.
     EXPECT_CALL(*listener, onProgressUpdated(1));
+    EXPECT_CALL(*listener, onProgress(12));  // 1/12 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -398,6 +851,7 @@
 
     // Third update should be sent because it reaches threshold (6 - 1 = 5).
     EXPECT_CALL(*listener, onProgressUpdated(6));
+    EXPECT_CALL(*listener, onProgress(75));  // 6/8 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -479,6 +933,32 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE(
+            "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() "
+            "on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n");
+        return;
+    }
+
+    // Same test as above, but with unroot property set, which will override su availability.
+    SetUnroot(true);
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+    // AsRoot is ineffective.
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
+}
+
 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
     if (!IsStandalone()) {
         // TODO: temporarily disabled because it might cause other tests to fail after dropping
@@ -521,6 +1001,32 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE(
+            "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() "
+            "on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n");
+        return;
+    }
+    // Same test as above, but with unroot property set, which will override su availability.
+    SetUnroot(true);
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    // It's a userdebug build, so "su root" should be available, but unroot=true overrides it.
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
 TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
     EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
     EXPECT_THAT(out,
@@ -534,7 +1040,6 @@
     // We don't know the exact duration, so we check the prefix and suffix
     EXPECT_THAT(out, StartsWith("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No "
                                 "such file or directory\n"));
-    EXPECT_THAT(out, EndsWith("s was the duration of 'Y U NO EXIST?' ------\n"));
 }
 
 TEST_F(DumpstateTest, DumpFileSingleLine) {
@@ -574,8 +1079,7 @@
     EXPECT_THAT(err, IsEmpty());
     EXPECT_THAT(
         out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath + "single-line.txt:"));
-    EXPECT_THAT(out, HasSubstr("\n\t(skipped on dry run)\n------"));
-    EXPECT_THAT(out, EndsWith("s was the duration of 'Might as well dump. Dump!' ------\n"));
+    EXPECT_THAT(out, HasSubstr("\n\t(skipped on dry run)\n"));
 }
 
 TEST_F(DumpstateTest, DumpFileUpdateProgress) {
@@ -585,6 +1089,7 @@
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgressUpdated(5));
+    EXPECT_CALL(*listener, onProgress(16));  // 5/30 %
     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
 
     std::string progress_message =
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 022f4fc..0bb80dc 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -50,8 +50,6 @@
 #include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
-#include <debuggerd/client.h>
-#include <dumputils/dump_utils.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -82,8 +80,12 @@
 
 CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
 
+// TODO(111441001): Default DumpOptions to sensible values.
 Dumpstate::Dumpstate(const std::string& version)
-    : pid_(getpid()), version_(version), now_(time(nullptr)) {
+    : pid_(getpid()),
+      options_(new Dumpstate::DumpOptions()),
+      version_(version),
+      now_(time(nullptr)) {
 }
 
 Dumpstate& Dumpstate::GetInstance() {
@@ -91,8 +93,8 @@
     return singleton_;
 }
 
-DurationReporter::DurationReporter(const std::string& title, bool log_only)
-    : title_(title), log_only_(log_only) {
+DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
+    : title_(title), logcat_only_(logcat_only) {
     if (!title_.empty()) {
         started_ = Nanotime();
     }
@@ -100,14 +102,16 @@
 
 DurationReporter::~DurationReporter() {
     if (!title_.empty()) {
-        uint64_t elapsed = Nanotime() - started_;
-        if (log_only_) {
-            MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
-        } else {
-            // Use "Yoda grammar" to make it easier to grep|sort sections.
-            printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC,
-                   title_.c_str());
+        float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
+        if (elapsed < .5f) {
+            return;
         }
+        MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
+        if (logcat_only_) {
+            return;
+        }
+        // Use "Yoda grammar" to make it easier to grep|sort sections.
+        printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
     }
 }
 
@@ -225,7 +229,11 @@
 }
 
 std::string Dumpstate::GetPath(const std::string& suffix) const {
-    return android::base::StringPrintf("%s/%s-%s%s", bugreport_dir_.c_str(), base_name_.c_str(),
+    return GetPath(bugreport_internal_dir_, suffix);
+}
+
+std::string Dumpstate::GetPath(const std::string& directory, const std::string& suffix) const {
+    return android::base::StringPrintf("%s/%s-%s%s", directory.c_str(), base_name_.c_str(),
                                        name_.c_str(), suffix.c_str());
 }
 
@@ -272,6 +280,12 @@
 
     if (header) printf("\n------ %s ------\n", header);
     while ((de = readdir(d))) {
+        if (ds.IsUserConsentDenied()) {
+            MYLOGE(
+                "Returning early because user denied consent to share bugreport with calling app.");
+            closedir(d);
+            return;
+        }
         int pid;
         int fd;
         char cmdpath[255];
@@ -344,6 +358,12 @@
     func(pid, pid, cmdline);
 
     while ((de = readdir(d))) {
+        if (ds.IsUserConsentDenied()) {
+            MYLOGE(
+                "Returning early because user denied consent to share bugreport with calling app.");
+            closedir(d);
+            return;
+        }
         int tid;
         int fd;
         char commpath[255];
@@ -525,13 +545,13 @@
     if (PropertiesHelper::IsDryRun()) return;
 
     /* Get size of kernel buffer */
-    int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+    int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
     if (size <= 0) {
         printf("Unexpected klogctl return value: %d\n\n", size);
         return;
     }
     char *buf = (char *) malloc(size + 1);
-    if (buf == NULL) {
+    if (buf == nullptr) {
         printf("memory allocation failed\n\n");
         return;
     }
@@ -598,7 +618,7 @@
     DurationReporter duration_reporter(title);
     DIR *dirp;
     struct dirent *d;
-    char *newpath = NULL;
+    char *newpath = nullptr;
     const char *slash = "/";
     int retval = 0;
 
@@ -611,7 +631,7 @@
         ++slash;
     }
     dirp = opendir(dir);
-    if (dirp == NULL) {
+    if (dirp == nullptr) {
         retval = -errno;
         MYLOGE("%s: %s\n", dir, strerror(errno));
         return retval;
@@ -620,7 +640,7 @@
     if (!dump_from_fd) {
         dump_from_fd = dump_file_from_fd;
     }
-    for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) {
+    for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
         if ((d->d_name[0] == '.')
          && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
           || (d->d_name[1] == '\0'))) {
@@ -648,7 +668,7 @@
             printf("*** %s: %s\n", newpath, strerror(errno));
             continue;
         }
-        (*dump_from_fd)(NULL, newpath, fd.get());
+        (*dump_from_fd)(nullptr, newpath, fd.get());
     }
     closedir(dirp);
     if (!title.empty()) {
@@ -702,12 +722,12 @@
     int s = android_get_control_socket(service);
     if (s < 0) {
         MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
-        exit(1);
+        return -1;
     }
     fcntl(s, F_SETFD, FD_CLOEXEC);
     if (listen(s, 4) < 0) {
         MYLOGE("listen(control socket): %s\n", strerror(errno));
-        exit(1);
+        return -1;
     }
 
     struct sockaddr addr;
@@ -715,18 +735,23 @@
     int fd = accept(s, &addr, &alen);
     if (fd < 0) {
         MYLOGE("accept(control socket): %s\n", strerror(errno));
-        exit(1);
+        return -1;
     }
 
     return fd;
 }
 
 /* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service) {
+bool redirect_to_socket(FILE* redirect, const char* service) {
     int fd = open_socket(service);
+    if (fd == -1) {
+        return false;
+    }
     fflush(redirect);
-    dup2(fd, fileno(redirect));
+    // TODO: handle dup2 failure
+    TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
     close(fd);
+    return true;
 }
 
 // TODO: should call is_valid_output_file and/or be merged into it.
@@ -756,7 +781,7 @@
     }
 }
 
-void _redirect_to_file(FILE *redirect, char *path, int truncate_flag) {
+bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
     create_parent_dirs(path);
 
     int fd = TEMP_FAILURE_RETRY(open(path,
@@ -764,292 +789,20 @@
                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
     if (fd < 0) {
         MYLOGE("%s: %s\n", path, strerror(errno));
-        exit(1);
+        return false;
     }
 
     TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
     close(fd);
+    return true;
 }
 
-void redirect_to_file(FILE *redirect, char *path) {
-    _redirect_to_file(redirect, path, O_TRUNC);
+bool redirect_to_file(FILE* redirect, char* path) {
+    return _redirect_to_file(redirect, path, O_TRUNC);
 }
 
-void redirect_to_existing_file(FILE *redirect, char *path) {
-    _redirect_to_file(redirect, path, O_APPEND);
-}
-
-const char* DumpTraces(const std::string& traces_path);
-const char* DumpTracesTombstoned(const std::string& traces_dir);
-
-/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
-const char *dump_traces() {
-    DurationReporter duration_reporter("DUMP TRACES");
-
-    const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
-    if (!traces_dir.empty()) {
-        return DumpTracesTombstoned(traces_dir);
-    }
-
-    const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
-    if (!traces_file.empty()) {
-        return DumpTraces(traces_file);
-    }
-
-    return nullptr;
-}
-
-const char* DumpTracesTombstoned(const std::string& traces_dir) {
-    const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
-
-    const size_t buf_size = temp_file_pattern.length() + 1;
-    std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
-    memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
-
-    // Create a new, empty file to receive all trace dumps.
-    //
-    // TODO: This can be simplified once we remove support for the old style
-    // dumps. We can have a file descriptor passed in to dump_traces instead
-    // of creating a file, closing it and then reopening it again.
-    android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
-    if (fd < 0) {
-        MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
-        return nullptr;
-    }
-
-    // Nobody should have access to this temporary file except dumpstate, but we
-    // temporarily grant 'read' to 'others' here because this file is created
-    // when tombstoned is still running as root, but dumped after dropping. This
-    // can go away once support for old style dumping has.
-    const int chmod_ret = fchmod(fd, 0666);
-    if (chmod_ret < 0) {
-        MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
-        return nullptr;
-    }
-
-    std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
-    if (proc.get() == nullptr) {
-        MYLOGE("opendir /proc failed: %s\n", strerror(errno));
-        return nullptr;
-    }
-
-    // Number of times process dumping has timed out. If we encounter too many
-    // failures, we'll give up.
-    int timeout_failures = 0;
-    bool dalvik_found = false;
-
-    const std::set<int> hal_pids = get_interesting_hal_pids();
-
-    struct dirent* d;
-    while ((d = readdir(proc.get()))) {
-        int pid = atoi(d->d_name);
-        if (pid <= 0) {
-            continue;
-        }
-
-        const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
-        std::string exe;
-        if (!android::base::Readlink(link_name, &exe)) {
-            continue;
-        }
-
-        bool is_java_process;
-        if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
-            // Don't bother dumping backtraces for the zygote.
-            if (IsZygote(pid)) {
-                continue;
-            }
-
-            dalvik_found = true;
-            is_java_process = true;
-        } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
-            is_java_process = false;
-        } else {
-            // Probably a native process we don't care about, continue.
-            continue;
-        }
-
-        // If 3 backtrace dumps fail in a row, consider debuggerd dead.
-        if (timeout_failures == 3) {
-            dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
-            break;
-        }
-
-        const uint64_t start = Nanotime();
-        const int ret = dump_backtrace_to_file_timeout(
-            pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
-            is_java_process ? 5 : 20, fd);
-
-        if (ret == -1) {
-            dprintf(fd, "dumping failed, likely due to a timeout\n");
-            timeout_failures++;
-            continue;
-        }
-
-        // We've successfully dumped stack traces, reset the failure count
-        // and write a summary of the elapsed time to the file and continue with the
-        // next process.
-        timeout_failures = 0;
-
-        dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
-                pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
-    }
-
-    if (!dalvik_found) {
-        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
-    }
-
-    return file_name_buf.release();
-}
-
-const char* DumpTraces(const std::string& traces_path) {
-    const char* result = NULL;
-    /* move the old traces.txt (if any) out of the way temporarily */
-    std::string anrtraces_path = traces_path + ".anr";
-    if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) {
-        MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), anrtraces_path.c_str(), strerror(errno));
-        return nullptr;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
-    }
-
-    /* create a new, empty traces.txt file to receive stack dumps */
-    int fd = TEMP_FAILURE_RETRY(
-        open(traces_path.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
-             0666)); /* -rw-rw-rw- */
-    if (fd < 0) {
-        MYLOGE("%s: %s\n", traces_path.c_str(), strerror(errno));
-        return nullptr;
-    }
-    int chmod_ret = fchmod(fd, 0666);
-    if (chmod_ret < 0) {
-        MYLOGE("fchmod on %s failed: %s\n", traces_path.c_str(), strerror(errno));
-        close(fd);
-        return nullptr;
-    }
-
-    /* Variables below must be initialized before 'goto' statements */
-    int dalvik_found = 0;
-    int ifd, wfd = -1;
-    std::set<int> hal_pids = get_interesting_hal_pids();
-
-    /* walk /proc and kill -QUIT all Dalvik processes */
-    DIR *proc = opendir("/proc");
-    if (proc == NULL) {
-        MYLOGE("/proc: %s\n", strerror(errno));
-        goto error_close_fd;
-    }
-
-    /* use inotify to find when processes are done dumping */
-    ifd = inotify_init();
-    if (ifd < 0) {
-        MYLOGE("inotify_init: %s\n", strerror(errno));
-        goto error_close_fd;
-    }
-
-    wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE);
-    if (wfd < 0) {
-        MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno));
-        goto error_close_ifd;
-    }
-
-    struct dirent *d;
-    while ((d = readdir(proc))) {
-        int pid = atoi(d->d_name);
-        if (pid <= 0) continue;
-
-        char path[PATH_MAX];
-        char data[PATH_MAX];
-        snprintf(path, sizeof(path), "/proc/%d/exe", pid);
-        ssize_t len = readlink(path, data, sizeof(data) - 1);
-        if (len <= 0) {
-            continue;
-        }
-        data[len] = '\0';
-
-        if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
-            /* skip zygote -- it won't dump its stack anyway */
-            snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
-            int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
-            len = read(cfd, data, sizeof(data) - 1);
-            close(cfd);
-            if (len <= 0) {
-                continue;
-            }
-            data[len] = '\0';
-            if (!strncmp(data, "zygote", strlen("zygote"))) {
-                continue;
-            }
-
-            ++dalvik_found;
-            uint64_t start = Nanotime();
-            if (kill(pid, SIGQUIT)) {
-                MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
-                continue;
-            }
-
-            /* wait for the writable-close notification from inotify */
-            struct pollfd pfd = { ifd, POLLIN, 0 };
-            int ret = poll(&pfd, 1, TRACE_DUMP_TIMEOUT_MS);
-            if (ret < 0) {
-                MYLOGE("poll: %s\n", strerror(errno));
-            } else if (ret == 0) {
-                MYLOGE("warning: timed out dumping pid %d\n", pid);
-            } else {
-                struct inotify_event ie;
-                read(ifd, &ie, sizeof(ie));
-            }
-
-            if (lseek(fd, 0, SEEK_END) < 0) {
-                MYLOGE("lseek: %s\n", strerror(errno));
-            } else {
-                dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid,
-                        (float)(Nanotime() - start) / NANOS_PER_SEC);
-            }
-        } else if (should_dump_native_traces(data) ||
-                   hal_pids.find(pid) != hal_pids.end()) {
-            /* dump native process if appropriate */
-            if (lseek(fd, 0, SEEK_END) < 0) {
-                MYLOGE("lseek: %s\n", strerror(errno));
-            } else {
-                static uint16_t timeout_failures = 0;
-                uint64_t start = Nanotime();
-
-                /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
-                if (timeout_failures == 3) {
-                    dprintf(fd, "too many stack dump failures, skipping...\n");
-                } else if (dump_backtrace_to_file_timeout(
-                        pid, kDebuggerdNativeBacktrace, 20, fd) == -1) {
-                    dprintf(fd, "dumping failed, likely due to a timeout\n");
-                    timeout_failures++;
-                } else {
-                    timeout_failures = 0;
-                }
-                dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid,
-                        (float)(Nanotime() - start) / NANOS_PER_SEC);
-            }
-        }
-    }
-
-    if (dalvik_found == 0) {
-        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
-    }
-
-    static std::string dumptraces_path = android::base::StringPrintf(
-        "%s/bugreport-%s", dirname(traces_path.c_str()), basename(traces_path.c_str()));
-    if (rename(traces_path.c_str(), dumptraces_path.c_str())) {
-        MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), dumptraces_path.c_str(),
-               strerror(errno));
-        goto error_close_ifd;
-    }
-    result = dumptraces_path.c_str();
-
-    /* replace the saved [ANR] traces.txt file */
-    rename(anrtraces_path.c_str(), traces_path.c_str());
-
-error_close_ifd:
-    close(ifd);
-error_close_fd:
-    close(fd);
-    return result;
+bool redirect_to_existing_file(FILE* redirect, char* path) {
+    return _redirect_to_file(redirect, path, O_APPEND);
 }
 
 void dump_route_tables() {
@@ -1084,7 +837,7 @@
     bool max_changed = progress_->Inc(delta_sec);
 
     // ...but only notifiy listeners when necessary.
-    if (!update_progress_) return;
+    if (!options_->do_progress_updates) return;
 
     int progress = progress_->Get();
     int max = progress_->GetMax();
@@ -1105,16 +858,22 @@
         fsync(control_socket_fd_);
     }
 
+    int percent = 100 * progress / max;
     if (listener_ != nullptr) {
-        if (progress % 100 == 0) {
-            // We don't want to spam logcat, so only log multiples of 100.
-            MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+        if (percent % 5 == 0) {
+            // We don't want to spam logcat, so only log multiples of 5.
+            MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
+                   percent);
         } else {
             // stderr is ignored on normal invocations, but useful when calling
             // /system/bin/dumpstate directly for debuggging.
-            fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+            fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
+                    progress, max, percent);
         }
+        // TODO(b/111441001): Remove in favor of onProgress
         listener_->onProgressUpdated(progress);
+
+        listener_->onProgress(percent);
     }
 }
 
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index f68b862..f99588f 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -20,8 +20,6 @@
     static_libs: [
         "libserviceutils",
     ],
-
-    clang: true,
 }
 
 //
@@ -36,7 +34,6 @@
     export_include_dirs: ["."],
 }
 
-
 //
 // Executable
 //
@@ -51,4 +48,15 @@
     ],
 }
 
-subdirs = ["tests"]
+cc_binary {
+    name: "dumpsys_vendor",
+    stem: "dumpsys",
+
+    vendor: true,
+
+    defaults: ["dumpsys_defaults"],
+
+    srcs: [
+        "main.cpp",
+    ],
+}
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/dumpsys/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 5412d4d..4811927 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -65,7 +65,7 @@
             "         -l: only list services, do not dump them\n"
             "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
             "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
-            "         --proto: filter services that support dumping data in proto format. Dumps"
+            "         --proto: filter services that support dumping data in proto format. Dumps\n"
             "               will be in proto format.\n"
             "         --priority LEVEL: filter services based on specified priority\n"
             "               LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
@@ -389,7 +389,7 @@
         auto time_left_ms = [end]() {
             auto now = std::chrono::steady_clock::now();
             auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
-            return std::max(diff.count(), 0ll);
+            return std::max(diff.count(), 0LL);
         };
 
         int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 84f3b02..c48a1e9 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -26,7 +26,7 @@
 
 class Dumpsys {
   public:
-    Dumpsys(android::IServiceManager* sm) : sm_(sm) {
+    explicit Dumpsys(android::IServiceManager* sm) : sm_(sm) {
     }
     /**
      * Main entry point into dumpsys.
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 5029352..3ada153 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -74,7 +74,7 @@
     explicit WriteOnFdAction(const std::string& output) : output_(output) {
     }
     virtual Result Perform(const ArgumentTuple& args) {
-        int fd = ::std::tr1::get<0>(args);
+        int fd = ::testing::get<0>(args);
         android::base::WriteStringToFd(output_, fd);
     }
 
@@ -371,8 +371,8 @@
                                    IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
     ExpectCheckService("Locksmith");
     ExpectCheckService("Valet");
-    ExpectDumpWithArgs("Locksmith", {"-a", "--dump-priority", "NORMAL"}, "dump1");
-    ExpectDumpWithArgs("Valet", {"-a", "--dump-priority", "NORMAL"}, "dump2");
+    ExpectDumpWithArgs("Locksmith", {"--dump-priority", "NORMAL", "-a"}, "dump1");
+    ExpectDumpWithArgs("Valet", {"--dump-priority", "NORMAL", "-a"}, "dump2");
 
     CallMain({"--priority", "NORMAL"});
 
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index d5b3372..d398559 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -29,7 +29,7 @@
     mContext(EGL_NO_CONTEXT),
     mDummySurface(EGL_NO_SURFACE),
     mConfig(0),
-    mShaderPrograms(NULL),
+    mShaderPrograms(nullptr),
     mDitherTexture(0) {
 }
 
@@ -101,12 +101,12 @@
 }
 
 void GLHelper::tearDown() {
-    if (mShaderPrograms != NULL) {
+    if (mShaderPrograms != nullptr) {
         delete[] mShaderPrograms;
-        mShaderPrograms = NULL;
+        mShaderPrograms = nullptr;
     }
 
-    if (mSurfaceComposerClient != NULL) {
+    if (mSurfaceComposerClient != nullptr) {
         mSurfaceComposerClient->dispose();
         mSurfaceComposerClient.clear();
     }
@@ -210,7 +210,7 @@
     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
 
     sp<ANativeWindow> anw = new Surface(producer);
-    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
+    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
     if (s == EGL_NO_SURFACE) {
         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
         return false;
@@ -222,9 +222,9 @@
 }
 
 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
-    sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
-    if (dpy == NULL) {
-        fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
+    const sp<IBinder> dpy = mSurfaceComposerClient->getInternalDisplayToken();
+    if (dpy == nullptr) {
+        fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n");
         return false;
     }
 
@@ -247,7 +247,7 @@
     bool result;
     status_t err;
 
-    if (mSurfaceComposerClient == NULL) {
+    if (mSurfaceComposerClient == nullptr) {
         mSurfaceComposerClient = new SurfaceComposerClient;
     }
     err = mSurfaceComposerClient->initCheck();
@@ -258,7 +258,7 @@
 
     sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface(
             String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0);
-    if (sc == NULL || !sc->isValid()) {
+    if (sc == nullptr || !sc->isValid()) {
         fprintf(stderr, "Failed to create SurfaceControl.\n");
         return false;
     }
@@ -275,7 +275,7 @@
             .apply();
 
     sp<ANativeWindow> anw = sc->getSurface();
-    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
+    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
     if (s == EGL_NO_SURFACE) {
         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
         return false;
@@ -294,7 +294,7 @@
         return false;
     }
 
-    glShaderSource(shader, 1, &src, NULL);
+    glShaderSource(shader, 1, &src, nullptr);
     glCompileShader(shader);
 
     GLint compiled = 0;
@@ -305,7 +305,7 @@
         if (infoLen) {
             char* buf = new char[infoLen];
             if (buf) {
-                glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                glGetShaderInfoLog(shader, infoLen, nullptr, buf);
                 fprintf(stderr, "Shader compile log:\n%s\n", buf);
                 delete[] buf;
             }
@@ -318,21 +318,21 @@
 }
 
 static void printShaderSource(const char* const* src) {
-    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
+    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
         fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
     }
 }
 
 static const char* makeShaderString(const char* const* src) {
     size_t len = 0;
-    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
+    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
         // The +1 is for the '\n' that will be added.
         len += strlen(src[i]) + 1;
     }
 
     char* result = new char[len+1];
     char* end = result;
-    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
+    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
         strcpy(end, src[i]);
         end += strlen(src[i]);
         *end = '\n';
@@ -376,7 +376,7 @@
         if (bufLength) {
             char* buf = new char[bufLength];
             if (buf) {
-                glGetProgramInfoLog(program, bufLength, NULL, buf);
+                glGetProgramInfoLog(program, bufLength, nullptr, buf);
                 fprintf(stderr, "Program link log:\n%s\n", buf);
                 delete[] buf;
             }
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index 3d7cac0..7ceb397 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -284,7 +284,7 @@
 public:
 
     Layer() :
-        mGLHelper(NULL),
+        mGLHelper(nullptr),
         mSurface(EGL_NO_SURFACE) {
     }
 
@@ -316,23 +316,23 @@
     }
 
     void tearDown() {
-        if (mComposer != NULL) {
+        if (mComposer != nullptr) {
             mComposer->tearDown();
             delete mComposer;
-            mComposer = NULL;
+            mComposer = nullptr;
         }
 
-        if (mRenderer != NULL) {
+        if (mRenderer != nullptr) {
             mRenderer->tearDown();
             delete mRenderer;
-            mRenderer = NULL;
+            mRenderer = nullptr;
         }
 
         if (mSurface != EGL_NO_SURFACE) {
             mGLHelper->destroySurface(&mSurface);
             mGLConsumer->abandon();
         }
-        mGLHelper = NULL;
+        mGLHelper = nullptr;
         mGLConsumer.clear();
     }
 
@@ -377,7 +377,7 @@
         mDesc(desc),
         mInstance(instance),
         mNumLayers(countLayers(desc)),
-        mGLHelper(NULL),
+        mGLHelper(nullptr),
         mSurface(EGL_NO_SURFACE),
         mWindowSurface(EGL_NO_SURFACE) {
     }
@@ -443,7 +443,7 @@
             mLayers[i].tearDown();
         }
 
-        if (mGLHelper != NULL) {
+        if (mGLHelper != nullptr) {
             if (mWindowSurface != EGL_NO_SURFACE) {
                 mGLHelper->destroySurface(&mWindowSurface);
             }
@@ -453,7 +453,7 @@
             mSurfaceControl.clear();
             mGLHelper->tearDown();
             delete mGLHelper;
-            mGLHelper = NULL;
+            mGLHelper = nullptr;
         }
     }
 
@@ -553,7 +553,7 @@
     static size_t countLayers(const BenchmarkDesc& desc) {
         size_t i;
         for (i = 0; i < MAX_NUM_LAYERS; i++) {
-            if (desc.layers[i].rendererFactory == NULL) {
+            if (desc.layers[i].rendererFactory == nullptr) {
                 break;
             }
         }
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 94c3102..c80ae3b 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -14,9 +14,12 @@
         "CacheItem.cpp",
         "CacheTracker.cpp",
         "InstalldNativeService.cpp",
+        "QuotaUtils.cpp",
         "dexopt.cpp",
         "globals.cpp",
         "utils.cpp",
+        "utils_default.cpp",
+        "view_compiler.cpp",
         ":installd_aidl",
     ],
     header_libs: [
@@ -29,10 +32,27 @@
         "libcutils",
         "liblog",
         "liblogwrap",
+        "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+
     clang: true,
 
     tidy: true,
@@ -59,6 +79,26 @@
     aidl: {
         export_aidl_headers: true,
     },
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+}
+
+cc_library_headers {
+    name: "libinstalld_headers",
+    export_include_dirs: ["."],
 }
 
 //
@@ -73,6 +113,25 @@
     static_libs: ["libdiskusage"],
 
     init_rc: ["installd.rc"],
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
+
+    // Needs to be wherever installd is as it's execed by
+    // installd.
+    required: [ "migrate_legacy_obb_data.sh" ],
 }
 
 // OTA chroot tool
@@ -85,10 +144,26 @@
     ],
     clang: true,
 
-    srcs: ["otapreopt_chroot.cpp"],
+    srcs: [
+        "otapreopt_chroot.cpp",
+        "otapreopt_utils.cpp",
+    ],
     shared_libs: [
         "libbase",
+        "libbinder",
         "liblog",
+        "libprotobuf-cpp-full",
+        "libselinux",
+        "libutils",
+        "libziparchive",
+    ],
+    static_libs: [
+        "libapex",
+        "libapexd",
+        "lib_apex_manifest_proto",
+        "libavb",
+        "libdm",
+        "libvold_binder",
     ],
 }
 
@@ -108,10 +183,8 @@
         "-Wall",
         "-Werror"
     ],
-    clang: true,
 
-    srcs: [
-        "otapreopt_parameters.cpp"],
+    srcs: ["otapreopt_parameters.cpp"],
 
     export_include_dirs: ["."],
 
@@ -119,8 +192,75 @@
         "libbase",
         "libcutils",
         "liblog",
+        "libprocessgroup",
         "libutils",
     ],
 }
 
-subdirs = ["tests"]
+//
+//  OTA Executable
+//
+
+cc_binary {
+    name: "otapreopt",
+    cflags: [
+        "-Wall",
+        "-Werror"
+    ],
+
+    srcs: [
+        "dexopt.cpp",
+        "globals.cpp",
+        "otapreopt.cpp",
+        "otapreopt_utils.cpp",
+        "utils.cpp",
+        "utils_default.cpp",
+        "view_compiler.cpp",
+    ],
+
+    header_libs: ["dex2oat_headers"],
+
+    static_libs: [
+        "libartimagevalues",
+        "libdiskusage",
+        "libotapreoptparameters",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+        "libprocessgroup",
+        "libselinux",
+        "libutils",
+        "server_configurable_flags",
+    ],
+}
+
+// OTA slot script
+sh_binary {
+    name: "otapreopt_slot",
+    src: "otapreopt_slot.sh",
+    init_rc: ["otapreopt.rc"],
+}
+
+// OTA postinstall script
+sh_binary {
+    name: "otapreopt_script",
+    src: "otapreopt_script.sh",
+    // Let this depend on otapreopt, the chroot tool and the slot script,
+    // so we just have to mention one in a configuration.
+    required: [
+        "otapreopt",
+        "otapreopt_chroot",
+        "otapreopt_slot",
+    ],
+}
+
+// Script to migrate legacy obb data.
+sh_binary {
+    name: "migrate_legacy_obb_data.sh",
+    src: "migrate_legacy_obb_data.sh"
+}
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
deleted file mode 100644
index a4f95da..0000000
--- a/cmds/installd/Android.mk
+++ /dev/null
@@ -1,64 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#
-# OTA Executable
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := otapreopt
-LOCAL_CFLAGS := -Wall -Werror
-
-# Base & ASLR boundaries for boot image creation.
-ifndef LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA
-  LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA := -0x1000000
-else
-  LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA := $(LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
-endif
-ifndef LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA
-  LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA := 0x1000000
-else
-  LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA := $(LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
-endif
-LOCAL_CFLAGS += -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
-LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
-LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
-
-LOCAL_SRC_FILES := otapreopt.cpp otapreopt_parameters.cpp globals.cpp utils.cpp dexopt.cpp
-LOCAL_HEADER_LIBRARIES := dex2oat_headers
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcrypto \
-    libcutils \
-    liblog \
-    liblogwrap \
-    libselinux \
-    libutils \
-
-LOCAL_STATIC_LIBRARIES := libdiskusage
-LOCAL_CLANG := true
-include $(BUILD_EXECUTABLE)
-
-# OTA slot script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_slot
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_slot.sh
-LOCAL_INIT_RC := otapreopt.rc
-
-include $(BUILD_PREBUILT)
-
-# OTA postinstall script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_script
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_script.sh
-
-# Let this depend on otapreopt, the chroot tool and the slot script, so we just have to mention one
-# in a configuration.
-LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
-
-include $(BUILD_PREBUILT)
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 515f915..e29ff4c 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -73,7 +73,7 @@
         FTS *fts;
         FTSENT *p;
         char *argv[] = { (char*) path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             PLOG(WARNING) << "Failed to fts_open " << path;
             return -1;
         }
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index ea0cd9e..8b868fb 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -19,13 +19,13 @@
 #include "CacheTracker.h"
 
 #include <fts.h>
-#include <sys/quota.h>
 #include <sys/xattr.h>
 #include <utils/Trace.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
+#include "QuotaUtils.h"
 #include "utils.h"
 
 using android::base::StringPrintf;
@@ -33,9 +33,13 @@
 namespace android {
 namespace installd {
 
-CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
-        cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
-        mItemsLoaded(false) {
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid)
+      : cacheUsed(0),
+        cacheQuota(0),
+        mUserId(userId),
+        mAppId(appId),
+        mItemsLoaded(false),
+        mUuid(uuid) {
 }
 
 CacheTracker::~CacheTracker() {
@@ -72,26 +76,18 @@
 bool CacheTracker::loadQuotaStats() {
     int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
     int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId);
-    if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) {
-        struct dqblk dq;
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-            return false;
+    if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) {
+        int64_t space;
+        if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) {
+            cacheUsed += space;
         } else {
-            cacheUsed += dq.dqb_curspace;
+            return false;
         }
 
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
-            }
-            return false;
+        if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) {
+            cacheUsed += space;
         } else {
-            cacheUsed += dq.dqb_curspace;
+            return false;
         }
         return true;
     } else {
@@ -103,7 +99,7 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(WARNING) << "Failed to fts_open " << path;
         return;
     }
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
index 44359b4..b0527e7 100644
--- a/cmds/installd/CacheTracker.h
+++ b/cmds/installd/CacheTracker.h
@@ -39,7 +39,7 @@
  */
 class CacheTracker {
 public:
-    CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+    CacheTracker(userid_t userId, appid_t appId, const std::string& uuid);
     ~CacheTracker();
 
     std::string toString();
@@ -61,8 +61,8 @@
 private:
     userid_t mUserId;
     appid_t mAppId;
-    std::string mQuotaDevice;
     bool mItemsLoaded;
+    const std::string& mUuid;
 
     std::vector<std::string> mDataPaths;
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 860a68b..caac2e8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,7 +31,6 @@
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#include <sys/quota.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -40,8 +39,10 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -61,9 +62,11 @@
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
 #include "utils.h"
+#include "view_compiler.h"
 
 #include "CacheTracker.h"
 #include "MatchExtensionGen.h"
+#include "QuotaUtils.h"
 
 #ifndef LOG_TAG
 #define LOG_TAG "installd"
@@ -75,9 +78,13 @@
 namespace android {
 namespace installd {
 
+// An uuid used in unit tests.
+static constexpr const char* kTestUuid = "TEST";
+
+static constexpr const mode_t kRollbackFolderMode = 0700;
+
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
-static constexpr const char* kPropHasReserved = "vold.has_reserved";
 
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
@@ -95,15 +102,6 @@
 static constexpr size_t kSha256Size = 32;
 static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
 
-// NOTE: keep in sync with Installer
-static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
-static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
-static constexpr int FLAG_USE_QUOTA = 1 << 12;
-static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
-static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
-static constexpr int FLAG_FORCE = 1 << 16;
-
 namespace {
 
 constexpr const char* kDump = "android.permission.DUMP";
@@ -163,8 +161,17 @@
     }
 }
 
+binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr<std::string>& uuid) {
+    if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) {
+        return ok();
+    } else {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                StringPrintf("UUID must be null or \"%s\", got: %s", kTestUuid, uuid->c_str()));
+    }
+}
+
 binder::Status checkArgumentPackageName(const std::string& packageName) {
-    if (is_valid_package_name(packageName.c_str())) {
+    if (is_valid_package_name(packageName)) {
         return ok();
     } else {
         return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
@@ -215,6 +222,13 @@
     }                                                       \
 }
 
+#define CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(uuid) {         \
+    auto status = checkArgumentUuidTestOrNull(uuid);        \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}                                                           \
+
 #define CHECK_ARGUMENT_PACKAGE_NAME(packageName) {          \
     binder::Status status =                                 \
             checkArgumentPackageName((packageName));        \
@@ -267,11 +281,6 @@
         for (const auto& n : mStorageMounts) {
             out << "    " << n.first << " = " << n.second << endl;
         }
-
-        out << endl << "Quota reverse mounts:" << endl;
-        for (const auto& n : mQuotaReverseMounts) {
-            out << "    " << n.first << " = " << n.second << endl;
-        }
     }
 
     {
@@ -352,55 +361,6 @@
     return 0;
 }
 
-/**
- * Ensure that we have a hard-limit quota to protect against abusive apps;
- * they should never use more than 90% of blocks or 50% of inodes.
- */
-static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED,
-        const std::string& device, uid_t uid) {
-    // Skip when reserved blocks are protecting us against abusive apps
-    if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
-    // Skip when device no quotas present
-    if (device.empty()) return 0;
-
-    struct dqblk dq;
-    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-            reinterpret_cast<char*>(&dq)) != 0) {
-        PLOG(WARNING) << "Failed to find quota for " << uid;
-        return -1;
-    }
-
-#if APPLY_HARD_QUOTAS
-    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
-        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-        struct statvfs stat;
-        if (statvfs(path.c_str(), &stat) != 0) {
-            PLOG(WARNING) << "Failed to statvfs " << path;
-            return -1;
-        }
-
-        dq.dqb_valid = QIF_LIMITS;
-        dq.dqb_bhardlimit =
-            (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
-        dq.dqb_ihardlimit = (stat.f_files / 2);
-        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            PLOG(WARNING) << "Failed to set hard quota for " << uid;
-            return -1;
-        } else {
-            LOG(DEBUG) << "Applied hard quotas for " << uid;
-            return 0;
-        }
-    } else {
-        // Hard quota already set; assume it's reasonable
-        return 0;
-    }
-#else
-    // Hard quotas disabled
-    return 0;
-#endif
-}
-
 static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
     if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
         return true;
@@ -515,10 +475,6 @@
             return error("Failed to restorecon " + path);
         }
 
-        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
-            return error("Failed to set hard quota " + path);
-        }
-
         if (!prepare_app_profile_dir(packageName, appId, userId)) {
             return error("Failed to prepare profiles for " + packageName);
         }
@@ -632,6 +588,41 @@
             }
         }
     }
+    if (flags & FLAG_STORAGE_EXTERNAL) {
+        std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+        for (const auto& n : mStorageMounts) {
+            auto extPath = n.second;
+            if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) {
+                extPath += StringPrintf("/%d", userId);
+            } else if (userId != 0) {
+                // TODO: support devices mounted under secondary users
+                continue;
+            }
+            if (flags & FLAG_CLEAR_CACHE_ONLY) {
+                // Clear only cached data from shared storage
+                auto path = StringPrintf("%s/Android/data/%s/cache", extPath.c_str(), pkgname);
+                if (delete_dir_contents(path, true) != 0) {
+                    res = error("Failed to delete contents of " + path);
+                }
+            } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+                // No code cache on shared storage
+            } else {
+                // Clear everything on shared storage
+                auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
+                if (delete_dir_contents(path, true) != 0) {
+                    res = error("Failed to delete contents of " + path);
+                }
+                path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
+                if (delete_dir_contents(path, true) != 0) {
+                    res = error("Failed to delete contents of " + path);
+                }
+                path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
+                if (delete_dir_contents(path, true) != 0) {
+                    res = error("Failed to delete contents of " + path);
+                }
+            }
+        }
+    }
     return res;
 }
 
@@ -693,6 +684,30 @@
         // Verify if it's ok to do that.
         destroy_app_reference_profile(packageName);
     }
+    if (flags & FLAG_STORAGE_EXTERNAL) {
+        std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+        for (const auto& n : mStorageMounts) {
+            auto extPath = n.second;
+            if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) {
+                extPath += StringPrintf("/%d", userId);
+            } else if (userId != 0) {
+                // TODO: support devices mounted under secondary users
+                continue;
+            }
+            auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname);
+            if (delete_dir_contents_and_dir(path, true) != 0) {
+                res = error("Failed to delete contents of " + path);
+            }
+            path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
+            if (delete_dir_contents_and_dir(path, true) != 0) {
+                res = error("Failed to delete contents of " + path);
+            }
+            path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
+            if (delete_dir_contents_and_dir(path, true) != 0) {
+                res = error("Failed to delete contents of " + path);
+            }
+        }
+    }
     return res;
 }
 
@@ -715,7 +730,7 @@
         auto ce_path = create_data_user_ce_path(uuid_, user);
         auto de_path = create_data_user_de_path(uuid_, user);
         char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             return error("Failed to fts_open");
         }
         while ((p = fts_read(fts)) != nullptr) {
@@ -775,7 +790,7 @@
                                 PLOG(WARNING) << "Failed to chmod " << p->fts_path;
                             }
                         }
-                        // Intentional fall through to also set GID
+                        [[fallthrough]]; // also set GID
                     case FTS_F:
                         if (chown(p->fts_path, -1, expected) != 0) {
                             PLOG(WARNING) << "Failed to chown " << p->fts_path;
@@ -804,6 +819,253 @@
     return ok();
 }
 
+static int32_t copy_directory_recursive(const char* from, const char* to) {
+    char *argv[] = {
+        (char*) kCpPath,
+        (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+        (char*) "-p", /* preserve timestamps, ownership, and permissions */
+        (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+        (char*) "-P", /* Do not follow symlinks [default] */
+        (char*) "-d", /* don't dereference symlinks */
+        (char*) from,
+        (char*) to
+    };
+
+    LOG(DEBUG) << "Copying " << from << " to " << to;
+    return android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+}
+
+binder::Status InstalldNativeService::snapshotAppData(
+        const std::unique_ptr<std::string>& volumeUuid,
+        const std::string& packageName, int32_t user, int32_t snapshotId,
+        int32_t storageFlags, int64_t* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+
+    binder::Status res = ok();
+    // Default result to 0, it will be populated with inode of ce data snapshot
+    // if FLAG_STORAGE_CE has been passed.
+    if (_aidl_return != nullptr) *_aidl_return = 0;
+
+    bool clear_ce_on_exit = false;
+    bool clear_de_on_exit = false;
+
+    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
+            &snapshotId] {
+        if (clear_de_on_exit) {
+            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
+                    package_name);
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+                LOG(WARNING) << "Failed to delete app data snapshot: " << to;
+            }
+        }
+
+        if (clear_ce_on_exit) {
+            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
+                    package_name);
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+                LOG(WARNING) << "Failed to delete app data snapshot: " << to;
+            }
+        }
+    };
+
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    // The app may not have any data at all, in which case it's OK to skip here.
+    auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name);
+    if (access(from_ce.c_str(), F_OK) != 0) {
+        LOG(INFO) << "Missing source " << from_ce;
+        return ok();
+    }
+
+    // ce_data_inode is not needed when FLAG_CLEAR_CACHE_ONLY is set.
+    binder::Status clear_cache_result = clearAppData(volumeUuid, packageName, user,
+            storageFlags | FLAG_CLEAR_CACHE_ONLY, 0);
+    if (!clear_cache_result.isOk()) {
+        // It should be fine to continue snapshot if we for some reason failed
+        // to clear cache.
+        LOG(WARNING) << "Failed to clear cache of app " << packageName;
+    }
+
+    // ce_data_inode is not needed when FLAG_CLEAR_CODE_CACHE_ONLY is set.
+    binder::Status clear_code_cache_result = clearAppData(volumeUuid, packageName, user,
+            storageFlags | FLAG_CLEAR_CODE_CACHE_ONLY, 0);
+    if (!clear_code_cache_result.isOk()) {
+        // It should be fine to continue snapshot if we for some reason failed
+        // to clear code_cache.
+        LOG(WARNING) << "Failed to clear code_cache of app " << packageName;
+    }
+
+    if (storageFlags & FLAG_STORAGE_DE) {
+        auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
+        auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
+
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
+        }
+
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        rc = copy_directory_recursive(from.c_str(), to.c_str());
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from + " to " + to);
+            clear_de_on_exit = true;
+            return res;
+        }
+    }
+
+    if (storageFlags & FLAG_STORAGE_CE) {
+        auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
+        auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
+
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
+        }
+
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        rc = copy_directory_recursive(from.c_str(), to.c_str());
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from + " to " + to);
+            clear_ce_on_exit = true;
+            return res;
+        }
+        if (_aidl_return != nullptr) {
+            auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+                    snapshotId, package_name);
+            rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
+            if (rc != 0) {
+                res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
+                clear_ce_on_exit = true;
+                return res;
+            }
+        }
+    }
+
+    return res;
+}
+
+binder::Status InstalldNativeService::restoreAppDataSnapshot(
+        const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
+        const int32_t appId, const std::string& seInfo, const int32_t user,
+        const int32_t snapshotId, int32_t storageFlags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+
+    auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
+            user, snapshotId, package_name);
+    auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
+            user, snapshotId, package_name);
+
+    const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
+        (access(from_ce.c_str(), F_OK) == 0);
+    const bool needs_de_rollback = (storageFlags & FLAG_STORAGE_DE) &&
+        (access(from_de.c_str(), F_OK) == 0);
+
+    if (!needs_ce_rollback && !needs_de_rollback) {
+        return ok();
+    }
+
+    // We know we're going to rollback one of the CE or DE data, so we clear
+    // application data first. Note that it's possible that we're asked to
+    // restore both CE & DE data but that one of the restores fail. Leaving the
+    // app with no data in those cases is arguably better than leaving the app
+    // with mismatched / stale data.
+    LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
+    // It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
+    // can only be called when user unlocks the phone, meaning that CE user data
+    // is decrypted.
+    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
+            0 /* ceDataInode */);
+    if (!res.isOk()) {
+        return res;
+    }
+
+    if (needs_ce_rollback) {
+        auto to_ce = create_data_user_ce_path(volume_uuid, user);
+        int rc = copy_directory_recursive(from_ce.c_str(), to_ce.c_str());
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from_ce + " to " + to_ce);
+            return res;
+        }
+    }
+
+    if (needs_de_rollback) {
+        auto to_de = create_data_user_de_path(volume_uuid, user);
+        int rc = copy_directory_recursive(from_de.c_str(), to_de.c_str());
+        if (rc != 0) {
+            if (needs_ce_rollback) {
+                auto ce_data = create_data_user_ce_package_path(volume_uuid, user, package_name);
+                LOG(WARNING) << "de_data rollback failed. Erasing rolled back ce_data " << ce_data;
+                if (delete_dir_contents(ce_data.c_str(), 1, nullptr) != 0) {
+                    LOG(WARNING) << "Failed to delete rolled back ce_data " << ce_data;
+                }
+            }
+            res = error(rc, "Failed copying " + from_de + " to " + to_de);
+            return res;
+        }
+    }
+
+    // Finally, restore the SELinux label on the app data.
+    return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo);
+}
+
+binder::Status InstalldNativeService::destroyAppDataSnapshot(
+        const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
+        const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
+        int32_t storageFlags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+
+    if (storageFlags & FLAG_STORAGE_DE) {
+        auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
+                user, snapshotId, package_name);
+
+        int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
+        if (res != 0) {
+            return error(res, "Failed clearing snapshot " + de_snapshot_path);
+        }
+    }
+
+    if (storageFlags & FLAG_STORAGE_CE) {
+        auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
+                user, snapshotId, package_name, ceSnapshotInode);
+        int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
+        if (res != 0) {
+            return error(res, "Failed clearing snapshot " + ce_snapshot_path);
+        }
+    }
+    return ok();
+}
+
+
 binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
         const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
         const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -828,19 +1090,7 @@
         auto to = create_data_app_package_path(to_uuid, data_app_name);
         auto to_parent = create_data_app_path(to_uuid);
 
-        char *argv[] = {
-            (char*) kCpPath,
-            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
-            (char*) "-p", /* preserve timestamps, ownership, and permissions */
-            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
-            (char*) "-P", /* Do not follow symlinks [default] */
-            (char*) "-d", /* don't dereference symlinks */
-            (char*) from.c_str(),
-            (char*) to_parent.c_str()
-        };
-
-        LOG(DEBUG) << "Copying " << from << " to " << to;
-        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+        int rc = copy_directory_recursive(from.c_str(), to_parent.c_str());
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             goto fail;
@@ -868,25 +1118,11 @@
             goto fail;
         }
 
-        char *argv[] = {
-            (char*) kCpPath,
-            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
-            (char*) "-p", /* preserve timestamps, ownership, and permissions */
-            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
-            (char*) "-P", /* Do not follow symlinks [default] */
-            (char*) "-d", /* don't dereference symlinks */
-            nullptr,
-            nullptr
-        };
-
         {
             auto from = create_data_user_de_package_path(from_uuid, user, package_name);
             auto to = create_data_user_de_path(to_uuid, user);
-            argv[6] = (char*) from.c_str();
-            argv[7] = (char*) to.c_str();
 
-            LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+            int rc = copy_directory_recursive(from.c_str(), to.c_str());
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -895,11 +1131,8 @@
         {
             auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
             auto to = create_data_user_ce_path(to_uuid, user);
-            argv[6] = (char*) from.c_str();
-            argv[7] = (char*) to.c_str();
 
-            LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+            int rc = copy_directory_recursive(from.c_str(), to.c_str());
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -922,20 +1155,20 @@
     // Nuke everything we might have already copied
     {
         auto to = create_data_app_package_path(to_uuid, data_app_name);
-        if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+        if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
             LOG(WARNING) << "Failed to rollback " << to;
         }
     }
     for (auto user : users) {
         {
             auto to = create_data_user_de_package_path(to_uuid, user, package_name);
-            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to rollback " << to;
             }
         }
         {
             auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
-            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to rollback " << to;
             }
         }
@@ -958,13 +1191,6 @@
         }
     }
 
-    // Data under /data/media doesn't have an app, but we still want
-    // to limit it to prevent abuse.
-    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
-            multiuser_get_uid(userId, AID_MEDIA_RW))) {
-        return error("Failed to set hard quota for media_rw");
-    }
-
     return ok();
 }
 
@@ -1011,9 +1237,9 @@
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     auto data_path = create_data_path(uuid_);
-    auto device = findQuotaDeviceForUuid(uuid);
     auto noop = (flags & FLAG_FREE_CACHE_NOOP);
 
     int64_t free = data_disk_free(data_path);
@@ -1045,10 +1271,10 @@
             auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
             char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
                     (char*) media_path.c_str(), nullptr };
-            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
                 return error("Failed to fts_open");
             }
-            while ((p = fts_read(fts)) != NULL) {
+            while ((p = fts_read(fts)) != nullptr) {
                 if (p->fts_info == FTS_D && p->fts_level == 1) {
                     uid_t uid = p->fts_statp->st_uid;
                     if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
@@ -1060,7 +1286,7 @@
                         search->second->addDataPath(p->fts_path);
                     } else {
                         auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
-                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+                                multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString));
                         tracker->addDataPath(p->fts_path);
                         {
                             std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
@@ -1225,53 +1451,26 @@
 }
 #endif
 
-static void collectQuotaStats(const std::string& device, int32_t userId,
+static void collectQuotaStats(const std::string& uuid, int32_t userId,
         int32_t appId, struct stats* stats, struct stats* extStats) {
-    if (device.empty()) return;
-
-    struct dqblk dq;
-
+    int64_t space;
     if (stats != nullptr) {
         uid_t uid = multiuser_get_uid(userId, appId);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            stats->dataSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+            stats->dataSize += space;
         }
 
         int cacheGid = multiuser_get_cache_gid(userId, appId);
         if (cacheGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
-#endif
-                stats->cacheSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+                stats->cacheSize += space;
             }
         }
 
         int sharedGid = multiuser_get_shared_gid(0, appId);
         if (sharedGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
-#endif
-                stats->codeSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) {
+                stats->codeSize += space;
             }
         }
     }
@@ -1279,32 +1478,16 @@
     if (extStats != nullptr) {
         int extGid = multiuser_get_ext_gid(userId, appId);
         if (extGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
-#endif
-                extStats->dataSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) {
+                extStats->dataSize += space;
             }
         }
 
         int extCacheGid = multiuser_get_ext_cache_gid(userId, appId);
         if (extCacheGid != -1) {
-            if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid,
-                    reinterpret_cast<char*>(&dq)) != 0) {
-                if (errno != ESRCH) {
-                    PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid;
-                }
-            } else {
-#if MEASURE_DEBUG
-                LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace;
-#endif
-                extStats->dataSize += dq.dqb_curspace;
-                extStats->cacheSize += dq.dqb_curspace;
+            if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) {
+                extStats->dataSize += space;
+                extStats->cacheSize += space;
             }
         }
     }
@@ -1398,11 +1581,11 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(ERROR) << "Failed to fts_open " << path;
         return;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         p->fts_number = p->fts_parent->fts_number;
         switch (p->fts_info) {
         case FTS_D:
@@ -1412,7 +1595,7 @@
                     && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
                 p->fts_number = 1;
             }
-            // Fall through to count the directory
+            [[fallthrough]]; // to count the directory
         case FTS_DEFAULT:
         case FTS_F:
         case FTS_SL:
@@ -1468,16 +1651,17 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     ATRACE_BEGIN("obb");
     for (const auto& packageName : packageNames) {
-        auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
+        auto obbCodePath = create_data_media_package_path(uuid_, userId,
+                "obb", packageName.c_str());
         calculate_tree_size(obbCodePath, &extStats.codeSize);
     }
     ATRACE_END();
@@ -1491,7 +1675,7 @@
         ATRACE_END();
 
         ATRACE_BEGIN("quota");
-        collectQuotaStats(device, userId, appId, &stats, &extStats);
+        collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
         ATRACE_END();
     } else {
         ATRACE_BEGIN("code");
@@ -1574,27 +1758,19 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        struct dqblk dq;
+        int64_t space;
 
         ATRACE_BEGIN("obb");
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
-            extStats.codeSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+            extStats.codeSize += space;
         }
         ATRACE_END();
 
@@ -1620,16 +1796,8 @@
 
         ATRACE_BEGIN("external");
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            extStats.dataSize += dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+            extStats.dataSize += space;
         }
         ATRACE_END();
 
@@ -1646,7 +1814,7 @@
         int64_t dataSize = extStats.dataSize;
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
-                collectQuotaStats(device, userId, appId, &stats, &extStats);
+                collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
 
 #if MEASURE_DEBUG
                 // Sleep to make sure we don't lose logs
@@ -1728,6 +1896,7 @@
     LOG(INFO) << "Measuring external " << userId;
 #endif
 
+    auto uuidString = uuid ? *uuid : "";
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     int64_t totalSize = 0;
@@ -1737,58 +1906,33 @@
     int64_t appSize = 0;
     int64_t obbSize = 0;
 
-    auto device = findQuotaDeviceForUuid(uuid);
-    if (device.empty()) {
+    if (!IsQuotaSupported(uuidString)) {
         flags &= ~FLAG_USE_QUOTA;
     }
 
     if (flags & FLAG_USE_QUOTA) {
-        struct dqblk dq;
+        int64_t space;
 
         ATRACE_BEGIN("quota");
         uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
-        if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
-                reinterpret_cast<char*>(&dq)) != 0) {
-            if (errno != ESRCH) {
-                PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
-            }
-        } else {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
-#endif
-            totalSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) {
+            totalSize = space;
         }
 
         gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
-#endif
-            audioSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) {
+            audioSize = space;
         }
         gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
-#endif
-            videoSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) {
+            videoSize = space;
         }
         gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
-#endif
-            imageSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) {
+            imageSize = space;
         }
-        if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
-                reinterpret_cast<char*>(&dq)) == 0) {
-#if MEASURE_DEBUG
-            LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
-#endif
-            obbSize = dq.dqb_curspace;
+        if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) {
+            obbSize = space;
         }
         ATRACE_END();
 
@@ -1797,7 +1941,7 @@
         memset(&extStats, 0, sizeof(extStats));
         for (auto appId : appIds) {
             if (appId >= AID_APP_START) {
-                collectQuotaStats(device, userId, appId, nullptr, &extStats);
+                collectQuotaStats(uuidString, userId, appId, nullptr, &extStats);
             }
         }
         appSize = extStats.dataSize;
@@ -1808,10 +1952,10 @@
         FTSENT *p;
         auto path = create_data_media_path(uuid_, userId);
         char *argv[] = { (char*) path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             return error("Failed to fts_open " + path);
         }
-        while ((p = fts_read(fts)) != NULL) {
+        while ((p = fts_read(fts)) != nullptr) {
             char* ext;
             int64_t size = (p->fts_statp->st_blocks * 512);
             switch (p->fts_info) {
@@ -1827,13 +1971,14 @@
                         }
                     }
                 }
-                // Fall through to always count against total
+                [[fallthrough]]; // always count against total
             case FTS_D:
                 // Ignore data belonging to specific apps
                 p->fts_number = p->fts_parent->fts_number;
                 if (p->fts_level == 1 && !strcmp(p->fts_name, "Android")) {
                     p->fts_number = 1;
                 }
+                [[fallthrough]]; // always count against total
             case FTS_DEFAULT:
             case FTS_SL:
             case FTS_SLNONE:
@@ -1848,7 +1993,8 @@
         ATRACE_END();
 
         ATRACE_BEGIN("obb");
-        auto obbPath = create_data_media_obb_path(uuid_, "");
+        auto obbPath = StringPrintf("%s/Android/obb",
+                create_data_media_path(uuid_, userId).c_str());
         calculate_tree_size(obbPath, &obbSize);
         ATRACE_END();
     }
@@ -1979,6 +2125,17 @@
     return res ? error(res, error_msg) : ok();
 }
 
+binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
+                                                     const std::string& packageName,
+                                                     const std ::string& outDexFile, int uid,
+                                                     bool* _aidl_return) {
+    const char* apk_path = apkPath.c_str();
+    const char* package_name = packageName.c_str();
+    const char* out_dex_file = outDexFile.c_str();
+    *_aidl_return = android::installd::view_compiler(apk_path, package_name, out_dex_file, uid);
+    return *_aidl_return ? ok() : error("viewcompiler failed");
+}
+
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
     std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -2024,8 +2181,14 @@
         return error("Failed to stat " + _pkgdir);
     }
 
+    char *con = nullptr;
+    if (lgetfilecon(pkgdir, &con) < 0) {
+        return error("Failed to lgetfilecon " + _pkgdir);
+    }
+
     if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
-        return error("Failed to chown " + _pkgdir);
+        res = error("Failed to chown " + _pkgdir);
+        goto out;
     }
 
     if (chmod(pkgdir, 0700) < 0) {
@@ -2040,7 +2203,7 @@
         }
     } else {
         if (S_ISDIR(libStat.st_mode)) {
-            if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
+            if (delete_dir_contents(libsymlink, 1, nullptr) < 0) {
                 res = error("Failed to delete " + _libsymlink);
                 goto out;
             }
@@ -2057,7 +2220,13 @@
         goto out;
     }
 
+    if (lsetfilecon(libsymlink, con) < 0) {
+        res = error("Failed to lsetfilecon " + _libsymlink);
+        goto out;
+    }
+
 out:
+    free(con);
     if (chmod(pkgdir, s.st_mode) < 0) {
         auto msg = "Failed to cleanup chmod " + _pkgdir;
         if (res.isOk()) {
@@ -2082,14 +2251,14 @@
 static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
 {
     execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk,
-            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+            StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
     PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
 }
 
 static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
 {
     execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk,
-            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+            StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
     PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
 }
 
@@ -2140,7 +2309,7 @@
 static int flatten_path(const char *prefix, const char *suffix,
         const char *overlay_path, char *idmap_path, size_t N)
 {
-    if (overlay_path == NULL || idmap_path == NULL) {
+    if (overlay_path == nullptr || idmap_path == nullptr) {
         return -1;
     }
     const size_t len_overlay_path = strlen(overlay_path);
@@ -2345,7 +2514,7 @@
     if (validate_apk_path(packageDir.c_str())) {
         return error("Invalid path " + packageDir);
     }
-    if (delete_dir_contents_and_dir(packageDir) != 0) {
+    if (rm_package_dir(packageDir) != 0) {
         return error("Failed to delete " + packageDir);
     }
     return ok();
@@ -2481,7 +2650,7 @@
                      std::to_string(shmSize));
     }
     auto data = std::unique_ptr<void, std::function<void (void *)>>(
-        mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
+        mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
         [contentSize] (void* ptr) {
           if (ptr != MAP_FAILED) {
             munmap(ptr, contentSize);
@@ -2584,7 +2753,12 @@
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
     mStorageMounts.clear();
-    mQuotaReverseMounts.clear();
+
+#if !BYPASS_QUOTA
+    if (!InvalidateQuotaMounts()) {
+        return error("Failed to read mounts");
+    }
+#endif
 
     std::ifstream in("/proc/mounts");
     if (!in.is_open()) {
@@ -2605,32 +2779,6 @@
             mStorageMounts[source] = target;
         }
 #endif
-
-#if !BYPASS_QUOTA
-        if (source.compare(0, 11, "/dev/block/") == 0) {
-            struct dqblk dq;
-            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
-                    reinterpret_cast<char*>(&dq)) == 0) {
-                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
-                mQuotaReverseMounts[target] = source;
-
-                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
-                // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
-                // only need hard limits enabled when we're not being protected
-                // by reserved blocks.
-                if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
-                    if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1,
-                            nullptr) != 0 && errno != EBUSY) {
-                        PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
-                    }
-                    if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1,
-                            nullptr) != 0 && errno != EBUSY) {
-                        PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
-                    }
-                }
-            }
-        }
-#endif
     }
     return ok();
 }
@@ -2648,16 +2796,10 @@
     return StringPrintf("%s/%u", resolved.c_str(), userid);
 }
 
-std::string InstalldNativeService::findQuotaDeviceForUuid(
-        const std::unique_ptr<std::string>& uuid) {
-    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
-    auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
-    return mQuotaReverseMounts[path];
-}
-
 binder::Status InstalldNativeService::isQuotaSupported(
-        const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) {
-    *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty();
+        const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
+    auto uuidString = uuid ? *uuid : "";
+    *_aidl_return = IsQuotaSupported(uuidString);
     return ok();
 }
 
@@ -2674,5 +2816,16 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::migrateLegacyObbData() {
+    ENFORCE_UID(AID_SYSTEM);
+    // NOTE: The lint warning doesn't apply to the use of system(3) with
+    // absolute parse and no command line arguments.
+    if (system("/system/bin/migrate_legacy_obb_data.sh") != 0) { // NOLINT(cert-env33-c)
+        LOG(ERROR) << "Unable to migrate legacy obb data";
+    }
+
+    return ok();
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index cebd3f9..2b7bf33 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -60,6 +60,16 @@
 
     binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
 
+    binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
+            const std::string& packageName, const int32_t user, const int32_t snapshotId,
+            int32_t storageFlags, int64_t* _aidl_return);
+    binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
+            const std::string& packageName, const int32_t appId, const std::string& seInfo,
+            const int32_t user, const int32_t snapshotId, int32_t storageFlags);
+    binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
+            const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
+            const int32_t snapshotId, int32_t storageFlags);
+
     binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
             const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
             int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -89,6 +99,9 @@
             const std::unique_ptr<std::string>& dexMetadataPath,
             const std::unique_ptr<std::string>& compilationReason);
 
+    binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
+                                  const std::string& outDexFile, int uid, bool* _aidl_return);
+
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
     binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
@@ -142,6 +155,8 @@
             const std::string& codePath, const std::unique_ptr<std::string>& dexMetadata,
             bool* _aidl_return);
 
+    binder::Status migrateLegacyObbData();
+
 private:
     std::recursive_mutex mLock;
 
@@ -150,14 +165,11 @@
 
     /* Map of all storage mounts from source to target */
     std::unordered_map<std::string, std::string> mStorageMounts;
-    /* Map of all quota mounts from target to source */
-    std::unordered_map<std::string, std::string> mQuotaReverseMounts;
 
     /* Map from UID to cache quota size */
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
     std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
-    std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/MatchExtensionGen.h b/cmds/installd/MatchExtensionGen.h
index fded6b7..35c3889 100644
--- a/cmds/installd/MatchExtensionGen.h
+++ b/cmds/installd/MatchExtensionGen.h
@@ -31,6 +31,7 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'p': case 'P':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
@@ -41,10 +42,15 @@
                         switch (ext[5]) {
                         case '\0': return AID_MEDIA_VIDEO;
                         }
+                        break;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'a': case 'A':
         switch (ext[1]) {
         case 'a': case 'A':
@@ -53,7 +59,9 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'i': case 'I':
             switch (ext[2]) {
             case 'f': case 'F':
@@ -63,56 +71,73 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 case 'f': case 'F':
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'm': case 'M':
             switch (ext[2]) {
             case 'r': case 'R':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 't': case 'T':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             case 'w': case 'W':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case 'i': case 'I':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'w': case 'W':
             switch (ext[2]) {
             case 'b': case 'B':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'b': case 'B':
         switch (ext[1]) {
         case 'm': case 'M':
@@ -121,8 +146,11 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'c': case 'C':
         switch (ext[1]) {
         case 'r': case 'R':
@@ -131,8 +159,11 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'd': case 'D':
         switch (ext[1]) {
         case 'i': case 'I':
@@ -141,23 +172,30 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'l': case 'L':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         }
+        break;
     case 'f': case 'F':
         switch (ext[1]) {
         case 'l': case 'L':
@@ -168,13 +206,18 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 }
+                break;
             case 'i': case 'I':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'g': case 'G':
         switch (ext[1]) {
         case 'i': case 'I':
@@ -183,15 +226,20 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'j': case 'J':
         switch (ext[1]) {
         case 'n': case 'N':
@@ -200,7 +248,9 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case 'e': case 'E':
@@ -210,13 +260,18 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'l': case 'L':
         switch (ext[1]) {
         case 's': case 'S':
@@ -225,12 +280,16 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'm': case 'M':
         switch (ext[1]) {
         case '3':
@@ -239,36 +298,46 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case '4':
             switch (ext[2]) {
             case 'a': case 'A':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'v': case 'V':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'k': case 'K':
             switch (ext[2]) {
             case 'a': case 'A':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'v': case 'V':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'o': case 'O':
             switch (ext[2]) {
             case 'v': case 'V':
@@ -280,23 +349,30 @@
                         switch (ext[5]) {
                         case '\0': return AID_MEDIA_VIDEO;
                         }
+                        break;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case '2':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case '3':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case '4':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'e': case 'E':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
@@ -307,8 +383,11 @@
                         switch (ext[5]) {
                         case '\0': return AID_MEDIA_AUDIO;
                         }
+                        break;
                     }
+                    break;
                 }
+                break;
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
@@ -316,16 +395,22 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_AUDIO;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'x': case 'X':
             switch (ext[2]) {
             case 'u': case 'U':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'n': case 'N':
         switch (ext[1]) {
         case 'e': case 'E':
@@ -334,15 +419,20 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'w': case 'W':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'o': case 'O':
         switch (ext[1]) {
         case 'g': case 'G':
@@ -351,19 +441,25 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'p': case 'P':
         switch (ext[1]) {
         case 'b': case 'B':
@@ -372,68 +468,88 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'c': case 'C':
             switch (ext[2]) {
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'e': case 'E':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'g': case 'G':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'l': case 'L':
             switch (ext[2]) {
             case 's': case 'S':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'g': case 'G':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case 'd': case 'D':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'q': case 'Q':
         switch (ext[1]) {
         case 't': case 'T':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         }
+        break;
     case 'r': case 'R':
         switch (ext[1]) {
         case 'a': case 'A':
@@ -443,30 +559,39 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 's': case 'S':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'g': case 'G':
             switch (ext[2]) {
             case 'b': case 'B':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'm': case 'M':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_AUDIO;
             }
+            break;
         case 'w': case 'W':
             switch (ext[2]) {
             case '2':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 's': case 'S':
         switch (ext[1]) {
         case 'd': case 'D':
@@ -475,21 +600,27 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'n': case 'N':
             switch (ext[2]) {
             case 'd': case 'D':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'w': case 'W':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case 'g': case 'G':
@@ -499,9 +630,13 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 't': case 'T':
         switch (ext[1]) {
         case 'i': case 'I':
@@ -513,13 +648,18 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 's': case 'S':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
             }
+            break;
         }
+        break;
     case 'v': case 'V':
         switch (ext[1]) {
         case 'o': case 'O':
@@ -528,8 +668,11 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'w': case 'W':
         switch (ext[1]) {
         case 'a': case 'A':
@@ -538,11 +681,14 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             }
+            break;
         case 'b': case 'B':
             switch (ext[2]) {
             case 'm': case 'M':
@@ -551,8 +697,11 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'e': case 'E':
             switch (ext[2]) {
             case 'b': case 'B':
@@ -561,12 +710,16 @@
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_VIDEO;
                     }
+                    break;
                 case 'p': case 'P':
                     switch (ext[4]) {
                     case '\0': return AID_MEDIA_IMAGE;
                     }
+                    break;
                 }
+                break;
             }
+            break;
         case 'm': case 'M':
             switch (ext[2]) {
             case '\0': return AID_MEDIA_VIDEO;
@@ -574,30 +727,39 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_AUDIO;
                 }
+                break;
             case 'v': case 'V':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'r': case 'R':
             switch (ext[2]) {
             case 'f': case 'F':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         case 'v': case 'V':
             switch (ext[2]) {
             case 'x': case 'X':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_VIDEO;
                 }
+                break;
             }
+            break;
         }
+        break;
     case 'x': case 'X':
         switch (ext[1]) {
         case 'b': case 'B':
@@ -606,22 +768,29 @@
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'p': case 'P':
             switch (ext[2]) {
             case 'm': case 'M':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         case 'w': case 'W':
             switch (ext[2]) {
             case 'd': case 'D':
                 switch (ext[3]) {
                 case '\0': return AID_MEDIA_IMAGE;
                 }
+                break;
             }
+            break;
         }
+        break;
     }
 
     return 0;
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
new file mode 100644
index 0000000..5673918
--- /dev/null
+++ b/cmds/installd/OWNERS
@@ -0,0 +1,10 @@
+set noparent
+
+agampe@google.com
+calin@google.com
+jsharkey@android.com
+maco@google.com
+mathieuc@google.com
+narayan@google.com
+ngeoffray@google.com
+toddke@google.com
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
new file mode 100644
index 0000000..b238dd3
--- /dev/null
+++ b/cmds/installd/QuotaUtils.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QuotaUtils.h"
+
+#include <fstream>
+#include <unordered_map>
+
+#include <sys/quota.h>
+
+#include <android-base/logging.h>
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+namespace {
+
+std::recursive_mutex mMountsLock;
+
+/* Map of all quota mounts from target to source */
+std::unordered_map<std::string, std::string> mQuotaReverseMounts;
+
+std::string& FindQuotaDeviceForUuid(const std::string& uuid) {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+    auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str());
+    return mQuotaReverseMounts[path];
+}
+
+} // namespace
+
+bool InvalidateQuotaMounts() {
+    std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
+    mQuotaReverseMounts.clear();
+
+    std::ifstream in("/proc/mounts");
+    if (!in.is_open()) {
+        return false;
+    }
+
+    std::string source;
+    std::string target;
+    std::string ignored;
+    while (!in.eof()) {
+        std::getline(in, source, ' ');
+        std::getline(in, target, ' ');
+        std::getline(in, ignored);
+
+        if (source.compare(0, 11, "/dev/block/") == 0) {
+            struct dqblk dq;
+            if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+                    reinterpret_cast<char*>(&dq)) == 0) {
+                LOG(DEBUG) << "Found quota mount " << source << " at " << target;
+                mQuotaReverseMounts[target] = source;
+            }
+        }
+    }
+    return true;
+}
+
+bool IsQuotaSupported(const std::string& uuid) {
+    return !FindQuotaDeviceForUuid(uuid).empty();
+}
+
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+}
+
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
new file mode 100644
index 0000000..9ad170f
--- /dev/null
+++ b/cmds/installd/QuotaUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_
+#define ANDROID_INSTALLD_QUOTA_UTILS_H_
+
+#include <memory>
+#include <string>
+
+namespace android {
+namespace installd {
+
+/* Clear and recompute the reverse mounts map */
+bool InvalidateQuotaMounts();
+
+/* Whether quota is supported in the device with the given uuid */
+bool IsQuotaSupported(const std::string& uuid);
+
+/* Get the current occupied space in bytes for a uid or -1 if fails */
+int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid);
+
+/* Get the current occupied space in bytes for a gid or -1 if fails */
+int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_QUOTA_UTILS_H_
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
new file mode 100644
index 0000000..287f2d9
--- /dev/null
+++ b/cmds/installd/TEST_MAPPING
@@ -0,0 +1,28 @@
+{
+  "presubmit": [
+    {
+      "name": "installd_cache_test"
+    },
+    {
+      "name": "installd_dexopt_test"
+    },
+    {
+      "name": "installd_otapreopt_test"
+    },
+    {
+      "name": "installd_service_test"
+    },
+    {
+      "name": "installd_utils_test"
+    },
+    {
+      "name": "CtsUsesLibraryHostTestCases"
+    },
+    {
+      "name": "CtsClassloaderSplitsHostTestCases"
+    },
+    {
+      "name": "CtsCompilationTestCases"
+    }
+  ]
+}
diff --git a/cmds/installd/art_helper/Android.bp b/cmds/installd/art_helper/Android.bp
new file mode 100644
index 0000000..c47dd72
--- /dev/null
+++ b/cmds/installd/art_helper/Android.bp
@@ -0,0 +1,12 @@
+// Inherit image values.
+art_global_defaults {
+    name: "libartimagevalues_defaults",
+}
+
+cc_library_static {
+    name: "libartimagevalues",
+    defaults: ["libartimagevalues_defaults"],
+    srcs: ["art_image_values.cpp"],
+    export_include_dirs: ["."],
+    cflags: ["-Wconversion"],
+}
diff --git a/cmds/installd/art_helper/art_image_values.cpp b/cmds/installd/art_helper/art_image_values.cpp
new file mode 100644
index 0000000..a139049
--- /dev/null
+++ b/cmds/installd/art_helper/art_image_values.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "art_image_values.h"
+
+namespace android {
+namespace installd {
+namespace art {
+
+uint32_t GetImageBaseAddress() {
+    return ART_BASE_ADDRESS;
+}
+int32_t GetImageMinBaseAddressDelta() {
+    return ART_BASE_ADDRESS_MIN_DELTA;
+}
+int32_t GetImageMaxBaseAddressDelta() {
+    return ART_BASE_ADDRESS_MAX_DELTA;
+}
+
+static_assert(ART_BASE_ADDRESS_MIN_DELTA < ART_BASE_ADDRESS_MAX_DELTA, "Inconsistent setup");
+
+}  // namespace art
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/art_helper/art_image_values.h b/cmds/installd/art_helper/art_image_values.h
new file mode 100644
index 0000000..20c44c9
--- /dev/null
+++ b/cmds/installd/art_helper/art_image_values.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H
+#define FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H
+
+#include <cstdint>
+
+namespace android {
+namespace installd {
+namespace art {
+
+uint32_t GetImageBaseAddress();
+int32_t GetImageMinBaseAddressDelta();
+int32_t GetImageMaxBaseAddressDelta();
+
+}  // namespace art
+}  // namespace installd
+}  // namespace android
+
+#endif  // FRAMEWORKS_NATIVE_CMDS_INSTALLD_ART_HELPER_ART_IMAGE_VALUES_H
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 91e20b7..26e9984 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -55,6 +55,8 @@
             @nullable @utf8InCpp String profileName,
             @nullable @utf8InCpp String dexMetadataPath,
             @nullable @utf8InCpp String compilationReason);
+    boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
+            @utf8InCpp String outDexFile, int uid);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
@@ -102,4 +104,27 @@
     boolean prepareAppProfile(@utf8InCpp String packageName,
         int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
         @nullable @utf8InCpp String dexMetadata);
+
+    long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+            int userId, int snapshotId, int storageFlags);
+    void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+            int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
+    void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
+
+    void migrateLegacyObbData();
+
+    const int FLAG_STORAGE_DE = 0x1;
+    const int FLAG_STORAGE_CE = 0x2;
+    const int FLAG_STORAGE_EXTERNAL = 0x4;
+
+    const int FLAG_CLEAR_CACHE_ONLY = 0x10;
+    const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
+
+    const int FLAG_FREE_CACHE_V2 = 0x100;
+    const int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 0x200;
+    const int FLAG_FREE_CACHE_NOOP = 0x400;
+
+    const int FLAG_USE_QUOTA = 0x1000;
+    const int FLAG_FORCE = 0x2000;
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 9615a75..dbb4f22 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "installed"
+#define LOG_TAG "installd"
 
 #include <array>
 #include <fcntl.h>
@@ -43,7 +43,9 @@
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
+#include <processgroup/sched_policy.h>
 #include <selinux/android.h>
+#include <server_configurable_flags/get_flags.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
@@ -54,6 +56,9 @@
 #include "utils.h"
 
 using android::base::EndsWith;
+using android::base::GetBoolProperty;
+using android::base::GetProperty;
+using android::base::ReadFdToString;
 using android::base::ReadFully;
 using android::base::StringPrintf;
 using android::base::WriteFully;
@@ -181,42 +186,17 @@
     return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
 }
 
-static int split_count(const char *str)
-{
-  char *ctx;
-  int count = 0;
-  char buf[kPropertyValueMax];
-
-  strlcpy(buf, str, sizeof(buf));
-  char *pBuf = buf;
-
-  while(strtok_r(pBuf, " ", &ctx) != NULL) {
-    count++;
-    pBuf = NULL;
-  }
-
-  return count;
-}
-
-static int split(char *buf, const char **argv)
-{
-  char *ctx;
-  int count = 0;
-  char *tok;
-  char *pBuf = buf;
-
-  while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) {
-    argv[count++] = tok;
-    pBuf = NULL;
-  }
-
-  return count;
+static std::vector<std::string> SplitBySpaces(const std::string& str) {
+    if (str.empty()) {
+        return {};
+    }
+    return android::base::Split(str, " ");
 }
 
 static const char* get_location_from_path(const char* path) {
     static constexpr char kLocationSeparator = '/';
     const char *location = strrchr(path, kLocationSeparator);
-    if (location == NULL) {
+    if (location == nullptr) {
         return path;
     } else {
         // Skip the separator character.
@@ -224,341 +204,352 @@
     }
 }
 
-[[ noreturn ]]
-static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
-        const char* input_file_name, const char* output_file_name, int swap_fd,
-        const char* instruction_set, const char* compiler_filter,
-        bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
-        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
-        bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
+// need to be performed between the fork and exec.
+class ExecVHelper {
+  public:
+    // Store a placeholder for the binary name.
+    ExecVHelper() : args_(1u, std::string()) {}
 
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
-                   << MAX_INSTRUCTION_SET_LEN;
-        exit(DexoptReturnCodes::kInstructionSetLength);
+    void PrepareArgs(const std::string& bin) {
+        CHECK(!args_.empty());
+        CHECK(args_[0].empty());
+        args_[0] = bin;
+        // Write char* into array.
+        for (const std::string& arg : args_) {
+            argv_.push_back(arg.c_str());
+        }
+        argv_.push_back(nullptr);  // Add null terminator.
     }
 
-    // Get the relative path to the input file.
-    const char* relative_input_file_name = get_location_from_path(input_file_name);
-
-    char dex2oat_Xms_flag[kPropertyValueMax];
-    bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
-
-    char dex2oat_Xmx_flag[kPropertyValueMax];
-    bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
-
-    char dex2oat_threads_buf[kPropertyValueMax];
-    bool have_dex2oat_threads_flag = get_property(post_bootcomplete
-                                                      ? "dalvik.vm.dex2oat-threads"
-                                                      : "dalvik.vm.boot-dex2oat-threads",
-                                                  dex2oat_threads_buf,
-                                                  NULL) > 0;
-    char dex2oat_threads_arg[kPropertyValueMax + 2];
-    if (have_dex2oat_threads_flag) {
-        sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
+    [[ noreturn ]]
+    void Exec(int exit_code) {
+        execv(argv_[0], (char * const *)&argv_[0]);
+        PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
+        exit(exit_code);
     }
 
-    char dex2oat_isa_features_key[kPropertyKeyMax];
-    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
-    char dex2oat_isa_features[kPropertyValueMax];
-    bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
-                                                  dex2oat_isa_features, NULL) > 0;
-
-    char dex2oat_isa_variant_key[kPropertyKeyMax];
-    sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
-    char dex2oat_isa_variant[kPropertyValueMax];
-    bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
-                                                 dex2oat_isa_variant, NULL) > 0;
-
-    const char *dex2oat_norelocation = "-Xnorelocate";
-    bool have_dex2oat_relocation_skip_flag = false;
-
-    char dex2oat_flags[kPropertyValueMax];
-    int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
-                                 dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
-    ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
-
-    // If we are booting without the real /data, don't spend time compiling.
-    char vold_decrypt[kPropertyValueMax];
-    bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
-    bool skip_compilation = (have_vold_decrypt &&
-                             (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
-                             (strcmp(vold_decrypt, "1") == 0)));
-
-    bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
-
-    char app_image_format[kPropertyValueMax];
-    char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
-    bool have_app_image_format =
-            image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-    if (have_app_image_format) {
-        sprintf(image_format_arg, "--image-format=%s", app_image_format);
-    }
-
-    char dex2oat_large_app_threshold[kPropertyValueMax];
-    bool have_dex2oat_large_app_threshold =
-            get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
-    char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
-    if (have_dex2oat_large_app_threshold) {
-        sprintf(dex2oat_large_app_threshold_arg,
-                "--very-large-app-threshold=%s",
-                dex2oat_large_app_threshold);
-    }
-
-    // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-    const char* dex2oat_bin = "/system/bin/dex2oat";
-    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
-    // Do not use dex2oatd for release candidates (give dex2oat more soak time).
-    bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
-    if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
-        if (access(kDex2oatDebugPath, X_OK) == 0) {
-            dex2oat_bin = kDex2oatDebugPath;
+    // Add an arg if it's not empty.
+    void AddArg(const std::string& arg) {
+        if (!arg.empty()) {
+            args_.push_back(arg);
         }
     }
 
-    bool generate_minidebug_info = kEnableMinidebugInfo &&
-            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
-                                           kMinidebugInfoSystemPropertyDefault);
-
-    static const char* RUNTIME_ARG = "--runtime-arg";
-
-    static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-
-    // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
-    // use arraysize instead.
-    char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
-    char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
-    char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
-    char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
-    char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
-    char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
-    char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
-    char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
-    char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
-    char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
-    char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
-    char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
-    bool have_dex2oat_swap_fd = false;
-    char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
-    bool have_dex2oat_image_fd = false;
-    char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
-    size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
-    char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
-    char class_loader_context_arg[class_loader_context_size];
-    if (class_loader_context != nullptr) {
-        snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
-            class_loader_context);
-    }
-
-    sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
-    sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
-    sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
-    sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
-    sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
-    sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
-    sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
-    sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
-    sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
-    if (swap_fd >= 0) {
-        have_dex2oat_swap_fd = true;
-        sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
-    }
-    if (image_fd >= 0) {
-        have_dex2oat_image_fd = true;
-        sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
-    }
-
-    if (have_dex2oat_Xms_flag) {
-        sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
-    }
-    if (have_dex2oat_Xmx_flag) {
-        sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
-    }
-    sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
-
-    // Compute compiler filter.
-
-    bool have_dex2oat_compiler_filter_flag = false;
-    if (skip_compilation) {
-        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) {
-        if (strlen(compiler_filter) + strlen("--compiler-filter=") <
-                    arraysize(dex2oat_compiler_filter_arg)) {
-            sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
-            have_dex2oat_compiler_filter_flag = true;
-        } else {
-            ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
-                  compiler_filter,
-                  kPropertyValueMax);
+    // Add a runtime arg if it's not empty.
+    void AddRuntimeArg(const std::string& arg) {
+        if (!arg.empty()) {
+            args_.push_back("--runtime-arg");
+            args_.push_back(arg);
         }
     }
 
-    if (!have_dex2oat_compiler_filter_flag) {
-        char dex2oat_compiler_filter_flag[kPropertyValueMax];
-        have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
-                                                         dex2oat_compiler_filter_flag, NULL) > 0;
-        if (have_dex2oat_compiler_filter_flag) {
-            sprintf(dex2oat_compiler_filter_arg,
-                    "--compiler-filter=%s",
-                    dex2oat_compiler_filter_flag);
-        }
-    }
+  protected:
+    // Holder arrays for backing arg storage.
+    std::vector<std::string> args_;
 
-    // Check whether all apps should be compiled debuggable.
-    if (!debuggable) {
-        char prop_buf[kPropertyValueMax];
-        debuggable =
-                (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
-                (prop_buf[0] == '1');
-    }
-    char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
-    if (profile_fd != -1) {
-        sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
-    }
+    // Argument poiners.
+    std::vector<const char*> argv_;
+};
 
-    // Get the directory of the apk to pass as a base classpath directory.
-    char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
-    std::string apk_dir(input_file_name);
-    unsigned long dir_index = apk_dir.rfind('/');
-    bool has_base_dir = dir_index != std::string::npos;
-    if (has_base_dir) {
-        apk_dir = apk_dir.substr(0, dir_index);
-        sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
-    }
-
-    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
-    std::string compilation_reason_arg = compilation_reason == nullptr
-            ? ""
-            : std::string("--compilation-reason=") + compilation_reason;
-
-    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
-    // Disable cdex if update input vdex is true since this combination of options is not
-    // supported.
-    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
-    const char* argv[9  // program name, mandatory arguments and the final NULL
-                     + (have_dex2oat_isa_variant ? 1 : 0)
-                     + (have_dex2oat_isa_features ? 1 : 0)
-                     + (have_dex2oat_Xms_flag ? 2 : 0)
-                     + (have_dex2oat_Xmx_flag ? 2 : 0)
-                     + (have_dex2oat_compiler_filter_flag ? 1 : 0)
-                     + (have_dex2oat_threads_flag ? 1 : 0)
-                     + (have_dex2oat_swap_fd ? 1 : 0)
-                     + (have_dex2oat_image_fd ? 1 : 0)
-                     + (have_dex2oat_relocation_skip_flag ? 2 : 0)
-                     + (generate_debug_info ? 1 : 0)
-                     + (debuggable ? 1 : 0)
-                     + (have_app_image_format ? 1 : 0)
-                     + dex2oat_flags_count
-                     + (profile_fd == -1 ? 0 : 1)
-                     + (class_loader_context != nullptr ? 1 : 0)
-                     + (has_base_dir ? 1 : 0)
-                     + (have_dex2oat_large_app_threshold ? 1 : 0)
-                     + (disable_cdex ? 1 : 0)
-                     + (generate_minidebug_info ? 1 : 0)
-                     + (target_sdk_version != 0 ? 2 : 0)
-                     + (enable_hidden_api_checks ? 2 : 0)
-                     + (dex_metadata_fd > -1 ? 1 : 0)
-                     + (compilation_reason != nullptr ? 1 : 0)];
-    int i = 0;
-    argv[i++] = dex2oat_bin;
-    argv[i++] = zip_fd_arg;
-    argv[i++] = zip_location_arg;
-    argv[i++] = input_vdex_fd_arg;
-    argv[i++] = output_vdex_fd_arg;
-    argv[i++] = oat_fd_arg;
-    argv[i++] = oat_location_arg;
-    argv[i++] = instruction_set_arg;
-    if (have_dex2oat_isa_variant) {
-        argv[i++] = instruction_set_variant_arg;
-    }
-    if (have_dex2oat_isa_features) {
-        argv[i++] = instruction_set_features_arg;
-    }
-    if (have_dex2oat_Xms_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_Xms_arg;
-    }
-    if (have_dex2oat_Xmx_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_Xmx_arg;
-    }
-    if (have_dex2oat_compiler_filter_flag) {
-        argv[i++] = dex2oat_compiler_filter_arg;
-    }
-    if (have_dex2oat_threads_flag) {
-        argv[i++] = dex2oat_threads_arg;
-    }
-    if (have_dex2oat_swap_fd) {
-        argv[i++] = dex2oat_swap_fd;
-    }
-    if (have_dex2oat_image_fd) {
-        argv[i++] = dex2oat_image_fd;
-    }
-    if (generate_debug_info) {
-        argv[i++] = "--generate-debug-info";
-    }
-    if (debuggable) {
-        argv[i++] = "--debuggable";
-    }
-    if (have_app_image_format) {
-        argv[i++] = image_format_arg;
-    }
-    if (have_dex2oat_large_app_threshold) {
-        argv[i++] = dex2oat_large_app_threshold_arg;
-    }
-    if (dex2oat_flags_count) {
-        i += split(dex2oat_flags, argv + i);
-    }
-    if (have_dex2oat_relocation_skip_flag) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = dex2oat_norelocation;
-    }
-    if (profile_fd != -1) {
-        argv[i++] = profile_arg;
-    }
-    if (has_base_dir) {
-        argv[i++] = base_dir;
-    }
-    if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg;
-    }
-    if (generate_minidebug_info) {
-        argv[i++] = kMinidebugDex2oatFlag;
-    }
-    if (disable_cdex) {
-        argv[i++] = kDisableCompactDexFlag;
-    }
-    if (target_sdk_version != 0) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = target_sdk_version_arg;
-    }
-    if (enable_hidden_api_checks) {
-        argv[i++] = RUNTIME_ARG;
-        argv[i++] = "-Xhidden-api-checks";
-    }
-
-    if (dex_metadata_fd > -1) {
-        argv[i++] = dex_metadata_fd_arg.c_str();
-    }
-
-    if(compilation_reason != nullptr) {
-        argv[i++] = compilation_reason_arg.c_str();
-    }
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
-
-    execv(dex2oat_bin, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
-    exit(DexoptReturnCodes::kDex2oatExec);
+static std::string MapPropertyToArg(const std::string& property,
+                                    const std::string& format,
+                                    const std::string& default_value = "") {
+  std::string prop = GetProperty(property, default_value);
+  if (!prop.empty()) {
+    return StringPrintf(format.c_str(), prop.c_str());
+  }
+  return "";
 }
 
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+static const char* select_execution_binary(const char* binary, const char* debug_binary,
+        bool background_job_compile) {
+    return select_execution_binary(
+        binary,
+        debug_binary,
+        background_job_compile,
+        is_debug_runtime(),
+        (android::base::GetProperty("ro.build.version.codename", "") == "REL"),
+        is_debuggable_build());
+}
+
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+// This is convenient method which is much easier to test because it doesn't read
+// system properties.
+const char* select_execution_binary(
+        const char* binary,
+        const char* debug_binary,
+        bool background_job_compile,
+        bool is_debug_runtime,
+        bool is_release,
+        bool is_debuggable_build) {
+    // Do not use debug binaries for release candidates (to give more soak time).
+    bool is_debug_bg_job = background_job_compile && is_debuggable_build && !is_release;
+
+    // If the runtime was requested to use libartd.so, we'll run the debug version - assuming
+    // the file is present (it may not be on images with very little space available).
+    bool useDebug = (is_debug_runtime || is_debug_bg_job) && (access(debug_binary, X_OK) == 0);
+
+    return useDebug ? debug_binary : binary;
+}
+
+// Namespace for Android Runtime flags applied during boot time.
+static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
+// Feature flag name for running the JIT in Zygote experiment, b/119800099.
+static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
+// Location of the apex image.
+static const char* kApexImage = "/system/framework/apex.art";
+
+class RunDex2Oat : public ExecVHelper {
+  public:
+    RunDex2Oat(int zip_fd,
+               int oat_fd,
+               int input_vdex_fd,
+               int output_vdex_fd,
+               int image_fd,
+               const char* input_file_name,
+               const char* output_file_name,
+               int swap_fd,
+               const char* instruction_set,
+               const char* compiler_filter,
+               bool debuggable,
+               bool post_bootcomplete,
+               bool background_job_compile,
+               int profile_fd,
+               const char* class_loader_context,
+               const std::string& class_loader_context_fds,
+               int target_sdk_version,
+               bool enable_hidden_api_checks,
+               bool generate_compact_dex,
+               int dex_metadata_fd,
+               const char* compilation_reason) {
+        // Get the relative path to the input file.
+        const char* relative_input_file_name = get_location_from_path(input_file_name);
+
+        std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+        std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+
+        const char* threads_property = post_bootcomplete
+                ? "dalvik.vm.dex2oat-threads"
+                : "dalvik.vm.boot-dex2oat-threads";
+        std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+
+        std::string bootclasspath;
+        char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+        if (dex2oat_bootclasspath != nullptr) {
+            bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
+        }
+        // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+        // BOOTCLASSPATH.
+
+        const std::string dex2oat_isa_features_key =
+                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+        std::string instruction_set_features_arg =
+            MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+
+        const std::string dex2oat_isa_variant_key =
+                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+        std::string instruction_set_variant_arg =
+            MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+
+        const char* dex2oat_norelocation = "-Xnorelocate";
+
+        const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+        std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+        ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+
+        // If we are booting without the real /data, don't spend time compiling.
+        std::string vold_decrypt = GetProperty("vold.decrypt", "");
+        bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                                vold_decrypt == "1";
+
+        std::string resolve_startup_string_arg =
+                MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
+                                 "--resolve-startup-const-strings=%s");
+        if (resolve_startup_string_arg.empty()) {
+          // If empty, fall back to system property.
+          resolve_startup_string_arg =
+                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+                                 "--resolve-startup-const-strings=%s");
+        }
+
+        const std::string image_block_size_arg =
+                MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
+                                 "--max-image-block-size=%s");
+
+        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+
+        std::string image_format_arg;
+        if (image_fd >= 0) {
+            image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
+        }
+
+        std::string dex2oat_large_app_threshold_arg =
+            MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
+
+
+        const char* dex2oat_bin = select_execution_binary(
+            kDex2oatPath, kDex2oatDebugPath, background_job_compile);
+
+        bool generate_minidebug_info = kEnableMinidebugInfo &&
+                GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
+
+        std::string boot_image;
+        std::string use_apex_image =
+            server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+                                                                 ENABLE_APEX_IMAGE,
+                                                                 /*default_value=*/ "");
+        if (use_apex_image == "true") {
+          boot_image = StringPrintf("-Ximage:%s", kApexImage);
+        } else {
+          boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+        }
+
+        // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+        // use arraysize instead.
+        std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+        std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+        std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+        std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+        std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+        std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+        std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+        std::string dex2oat_compiler_filter_arg;
+        std::string dex2oat_swap_fd;
+        std::string dex2oat_image_fd;
+        std::string target_sdk_version_arg;
+        if (target_sdk_version != 0) {
+            target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+        }
+        std::string class_loader_context_arg;
+        std::string class_loader_context_fds_arg;
+        if (class_loader_context != nullptr) {
+            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
+                                                    class_loader_context);
+            if (!class_loader_context_fds.empty()) {
+                class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
+                                                            class_loader_context_fds.c_str());
+            }
+        }
+
+        if (swap_fd >= 0) {
+            dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
+        }
+        if (image_fd >= 0) {
+            dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
+        }
+
+        // Compute compiler filter.
+        bool have_dex2oat_relocation_skip_flag = false;
+        if (skip_compilation) {
+            dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+            have_dex2oat_relocation_skip_flag = true;
+        } else if (compiler_filter != nullptr) {
+            dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
+        }
+
+        if (dex2oat_compiler_filter_arg.empty()) {
+            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+                                                           "--compiler-filter=%s");
+        }
+
+        // Check whether all apps should be compiled debuggable.
+        if (!debuggable) {
+            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+        }
+        std::string profile_arg;
+        if (profile_fd != -1) {
+            profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+        }
+
+        // Get the directory of the apk to pass as a base classpath directory.
+        std::string base_dir;
+        std::string apk_dir(input_file_name);
+        unsigned long dir_index = apk_dir.rfind('/');
+        bool has_base_dir = dir_index != std::string::npos;
+        if (has_base_dir) {
+            apk_dir = apk_dir.substr(0, dir_index);
+            base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
+        }
+
+        std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
+
+        std::string compilation_reason_arg = compilation_reason == nullptr
+                ? ""
+                : std::string("--compilation-reason=") + compilation_reason;
+
+        ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+        // Disable cdex if update input vdex is true since this combination of options is not
+        // supported.
+        const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+
+        AddArg(zip_fd_arg);
+        AddArg(zip_location_arg);
+        AddArg(input_vdex_fd_arg);
+        AddArg(output_vdex_fd_arg);
+        AddArg(oat_fd_arg);
+        AddArg(oat_location_arg);
+        AddArg(instruction_set_arg);
+
+        AddArg(instruction_set_variant_arg);
+        AddArg(instruction_set_features_arg);
+
+        AddRuntimeArg(boot_image);
+        AddRuntimeArg(bootclasspath);
+        AddRuntimeArg(dex2oat_Xms_arg);
+        AddRuntimeArg(dex2oat_Xmx_arg);
+
+        AddArg(resolve_startup_string_arg);
+        AddArg(image_block_size_arg);
+        AddArg(dex2oat_compiler_filter_arg);
+        AddArg(dex2oat_threads_arg);
+        AddArg(dex2oat_swap_fd);
+        AddArg(dex2oat_image_fd);
+
+        if (generate_debug_info) {
+            AddArg("--generate-debug-info");
+        }
+        if (debuggable) {
+            AddArg("--debuggable");
+        }
+        AddArg(image_format_arg);
+        AddArg(dex2oat_large_app_threshold_arg);
+
+        if (have_dex2oat_relocation_skip_flag) {
+            AddRuntimeArg(dex2oat_norelocation);
+        }
+        AddArg(profile_arg);
+        AddArg(base_dir);
+        AddArg(class_loader_context_arg);
+        AddArg(class_loader_context_fds_arg);
+        if (generate_minidebug_info) {
+            AddArg(kMinidebugDex2oatFlag);
+        }
+        if (disable_cdex) {
+            AddArg(kDisableCompactDexFlag);
+        }
+        AddRuntimeArg(target_sdk_version_arg);
+        if (enable_hidden_api_checks) {
+            AddRuntimeArg("-Xhidden-api-policy:enabled");
+        }
+
+        if (dex_metadata_fd > -1) {
+            AddArg(dex_metadata_fd_arg);
+        }
+
+        AddArg(compilation_reason_arg);
+
+        // Do not add args after dex2oat_flags, they should override others for debugging.
+        args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
+
+        PrepareArgs(dex2oat_bin);
+    }
+};
+
 /*
  * Whether dexopt should use a swap file when compiling an APK.
  *
@@ -580,13 +571,9 @@
     }
 
     // Check the "override" property. If it exists, return value == "true".
-    char dex2oat_prop_buf[kPropertyValueMax];
-    if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
-        if (strcmp(dex2oat_prop_buf, "true") == 0) {
-            return true;
-        } else {
-            return false;
-        }
+    std::string dex2oat_prop_buf = GetProperty("dalvik.vm.dex2oat-swap", "");
+    if (!dex2oat_prop_buf.empty()) {
+        return dex2oat_prop_buf == "true";
     }
 
     // Shortcut for default value. This is an implementation optimization for the process sketched
@@ -596,8 +583,7 @@
         return true;
     }
 
-    bool is_low_mem = property_get_bool("ro.config.low_ram", false);
-    if (is_low_mem) {
+    if (GetBoolProperty("ro.config.low_ram", false)) {
         return true;
     }
 
@@ -630,7 +616,7 @@
     // the app uid. If we cannot do that, there's no point in returning the fd
     // since dex2oat/profman will fail with SElinux denials.
     if (fchown(fd.get(), uid, uid) < 0) {
-        PLOG(ERROR) << "Could not chwon profile " << profile;
+        PLOG(ERROR) << "Could not chown profile " << profile;
         return invalid_unique_fd();
     }
     return fd;
@@ -711,117 +697,116 @@
     }
 }
 
-static void drop_capabilities(uid_t uid) {
-    if (setgid(uid) != 0) {
-        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
-        exit(DexoptReturnCodes::kSetGid);
-    }
-    if (setuid(uid) != 0) {
-        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
-        exit(DexoptReturnCodes::kSetUid);
-    }
-    // drop capabilities
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata[2];
-    memset(&capheader, 0, sizeof(capheader));
-    memset(&capdata, 0, sizeof(capdata));
-    capheader.version = _LINUX_CAPABILITY_VERSION_3;
-    if (capset(&capheader, &capdata[0]) < 0) {
-        PLOG(ERROR) << "capset failed";
-        exit(DexoptReturnCodes::kCapSet);
-    }
-}
-
 static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
 static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
 static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
-[[ noreturn ]]
-static void run_profman(const std::vector<unique_fd>& profile_fds,
-                        const unique_fd& reference_profile_fd,
-                        const std::vector<unique_fd>* apk_fds,
-                        const std::vector<std::string>* dex_locations,
-                        bool copy_and_update) {
-    const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+class RunProfman : public ExecVHelper {
+  public:
+   void SetupArgs(const std::vector<unique_fd>& profile_fds,
+                  const unique_fd& reference_profile_fd,
+                  const std::vector<unique_fd>& apk_fds,
+                  const std::vector<std::string>& dex_locations,
+                  bool copy_and_update,
+                  bool store_aggregation_counters) {
 
-    if (copy_and_update) {
-        CHECK_EQ(1u, profile_fds.size());
-        CHECK(apk_fds != nullptr);
-        CHECK_EQ(1u, apk_fds->size());
-    }
-    std::vector<std::string> profile_args(profile_fds.size());
-    for (size_t k = 0; k < profile_fds.size(); k++) {
-        profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get());
-    }
-    std::string reference_profile_arg = "--reference-profile-file-fd="
-            + std::to_string(reference_profile_fd.get());
+        // TODO(calin): Assume for now we run in the bg compile job (which is in
+        // most of the invocation). With the current data flow, is not very easy or
+        // clean to discover this in RunProfman (it will require quite a messy refactoring).
+        const char* profman_bin = select_execution_binary(
+            kProfmanPath, kProfmanDebugPath, /*background_job_compile=*/ true);
 
-    std::vector<std::string> apk_args;
-    if (apk_fds != nullptr) {
-        for (size_t k = 0; k < apk_fds->size(); k++) {
-            apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get()));
+        if (copy_and_update) {
+            CHECK_EQ(1u, profile_fds.size());
+            CHECK_EQ(1u, apk_fds.size());
         }
-    }
-
-    std::vector<std::string> dex_location_args;
-    if (dex_locations != nullptr) {
-        for (size_t k = 0; k < dex_locations->size(); k++) {
-            dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]);
+        if (reference_profile_fd != -1) {
+            AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
         }
+
+        for (const unique_fd& fd : profile_fds) {
+            AddArg("--profile-file-fd=" + std::to_string(fd.get()));
+        }
+
+        for (const unique_fd& fd : apk_fds) {
+            AddArg("--apk-fd=" + std::to_string(fd.get()));
+        }
+
+        for (const std::string& dex_location : dex_locations) {
+            AddArg("--dex-location=" + dex_location);
+        }
+
+        if (copy_and_update) {
+            AddArg("--copy-and-update-profile-key");
+        }
+
+        if (store_aggregation_counters) {
+            AddArg("--store-aggregation-counters");
+        }
+
+        // Do not add after dex2oat_flags, they should override others for debugging.
+        PrepareArgs(profman_bin);
     }
 
-    // program name, reference profile fd, the final NULL and the profile fds
-    const char* argv[3 + profile_args.size() + apk_args.size() + (copy_and_update ? 1 : 0)];
-    int i = 0;
-    argv[i++] = profman_bin;
-    argv[i++] = reference_profile_arg.c_str();
-    for (size_t k = 0; k < profile_args.size(); k++) {
-        argv[i++] = profile_args[k].c_str();
-    }
-    for (size_t k = 0; k < apk_args.size(); k++) {
-        argv[i++] = apk_args[k].c_str();
-    }
-    for (size_t k = 0; k < dex_location_args.size(); k++) {
-        argv[i++] = dex_location_args[k].c_str();
-    }
-    if (copy_and_update) {
-        argv[i++] = "--copy-and-update-profile-key";
+    void SetupMerge(const std::vector<unique_fd>& profiles_fd,
+                    const unique_fd& reference_profile_fd,
+                    const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
+                    const std::vector<std::string>& dex_locations = std::vector<std::string>(),
+                    bool store_aggregation_counters = false) {
+        SetupArgs(profiles_fd,
+                  reference_profile_fd,
+                  apk_fds,
+                  dex_locations,
+                  /*copy_and_update=*/false,
+                  store_aggregation_counters);
     }
 
-    // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
+    void SetupCopyAndUpdate(unique_fd&& profile_fd,
+                            unique_fd&& reference_profile_fd,
+                            unique_fd&& apk_fd,
+                            const std::string& dex_location) {
+        // The fds need to stay open longer than the scope of the function, so put them into a local
+        // variable vector.
+        profiles_fd_.push_back(std::move(profile_fd));
+        apk_fds_.push_back(std::move(apk_fd));
+        reference_profile_fd_ = std::move(reference_profile_fd);
+        std::vector<std::string> dex_locations = {dex_location};
+        SetupArgs(profiles_fd_,
+                  reference_profile_fd_,
+                  apk_fds_,
+                  dex_locations,
+                  /*copy_and_update=*/true,
+                  /*store_aggregation_counters=*/false);
+    }
 
-    execv(profman_bin, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
-    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
-}
+    void SetupDump(const std::vector<unique_fd>& profiles_fd,
+                   const unique_fd& reference_profile_fd,
+                   const std::vector<std::string>& dex_locations,
+                   const std::vector<unique_fd>& apk_fds,
+                   const unique_fd& output_fd) {
+        AddArg("--dump-only");
+        AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+        SetupArgs(profiles_fd,
+                  reference_profile_fd,
+                  apk_fds,
+                  dex_locations,
+                  /*copy_and_update=*/false,
+                  /*store_aggregation_counters=*/false);
+    }
 
-[[ noreturn ]]
-static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
-                              const unique_fd& reference_profile_fd,
-                              const std::vector<unique_fd>* apk_fds = nullptr,
-                              const std::vector<std::string>* dex_locations = nullptr) {
-    run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
-            /*copy_and_update*/false);
-}
+    void Exec() {
+        ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
+    }
 
-[[ noreturn ]]
-static void run_profman_copy_and_update(unique_fd&& profile_fd,
-                                        unique_fd&& reference_profile_fd,
-                                        unique_fd&& apk_fd,
-                                        const std::string& dex_location) {
-    std::vector<unique_fd> profiles_fd;
-    profiles_fd.push_back(std::move(profile_fd));
-    std::vector<unique_fd> apk_fds;
-    apk_fds.push_back(std::move(apk_fd));
-    std::vector<std::string> dex_locations;
-    dex_locations.push_back(dex_location);
+  private:
+    unique_fd reference_profile_fd_;
+    std::vector<unique_fd> profiles_fd_;
+    std::vector<unique_fd> apk_fds_;
+};
 
-    run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
-            /*copy_and_update*/true);
-}
+
 
 // Decides if profile guided compilation is needed or not based on existing profiles.
 // The location is the package name for primary apks or the dex path for secondary dex files.
@@ -841,11 +826,13 @@
         return false;
     }
 
+    RunProfman profman_merge;
+    profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        run_profman_merge(profiles_fd, reference_profile_fd);
+        profman_merge.Exec();
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -918,42 +905,6 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
-[[ noreturn ]]
-static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
-                             const unique_fd& reference_profile_fd,
-                             const std::vector<std::string>& dex_locations,
-                             const std::vector<unique_fd>& apk_fds,
-                             const unique_fd& output_fd) {
-    std::vector<std::string> profman_args;
-    static const char* PROFMAN_BIN = "/system/bin/profman";
-    profman_args.push_back(PROFMAN_BIN);
-    profman_args.push_back("--dump-only");
-    profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
-    if (reference_profile_fd != -1) {
-        profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
-                                            reference_profile_fd.get()));
-    }
-    for (size_t i = 0; i < profile_fds.size(); i++) {
-        profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
-    }
-    for (const std::string& dex_location : dex_locations) {
-        profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
-    }
-    for (size_t i = 0; i < apk_fds.size(); i++) {
-        profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
-    }
-    const char **argv = new const char*[profman_args.size() + 1];
-    size_t i = 0;
-    for (const std::string& profman_arg : profman_args) {
-        argv[i++] = profman_arg.c_str();
-    }
-    argv[i] = NULL;
-
-    execv(PROFMAN_BIN, (char * const *)argv);
-    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
-    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
-}
-
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
         const std::string& code_path) {
     std::vector<unique_fd> profile_fds;
@@ -990,12 +941,13 @@
     apk_fds.push_back(std::move(apk_fd));
 
 
+    RunProfman profman_dump;
+    profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
-                         apk_fds, output_fd);
+        profman_dump.Exec();
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1305,10 +1257,8 @@
     if (!generate_app_image) {
         return Dex2oatFileWrapper();
     }
-    char app_image_format[kPropertyValueMax];
-    bool have_app_image_format =
-            get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-    if (!have_app_image_format) {
+    std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
+    if (app_image_format.empty()) {
         return Dex2oatFileWrapper();
     }
     // Recreate is true since we do not want to modify a mapped image. If the app is
@@ -1569,70 +1519,82 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // 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, int vdex_fd, int oat_fd,
-        int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
-        bool profile_was_updated, bool downgrade,
-        const char* class_loader_context) {
-    CHECK_GE(zip_fd, 0);
-    const char* dexoptanalyzer_bin =
-            is_debug_runtime()
-                    ? "/system/bin/dexoptanalyzerd"
-                    : "/system/bin/dexoptanalyzer";
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+class RunDexoptAnalyzer : public ExecVHelper {
+ public:
+    RunDexoptAnalyzer(const std::string& dex_file,
+                      int vdex_fd,
+                      int oat_fd,
+                      int zip_fd,
+                      const std::string& instruction_set,
+                      const std::string& compiler_filter,
+                      bool profile_was_updated,
+                      bool downgrade,
+                      const char* class_loader_context,
+                      const std::string& class_loader_context_fds) {
+        CHECK_GE(zip_fd, 0);
 
-    if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
-        LOG(ERROR) << "Instruction set " << instruction_set
-                << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
-        return;
+        // We always run the analyzer in the background job.
+        const char* dexoptanalyzer_bin = select_execution_binary(
+             kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
+
+        std::string dex_file_arg = "--dex-file=" + dex_file;
+        std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+        std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+        std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+        std::string isa_arg = "--isa=" + instruction_set;
+        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;
+        }
+        std::string class_loader_context_fds_arg = "--class-loader-context-fds=";
+        if (!class_loader_context_fds.empty()) {
+            class_loader_context_fds_arg += class_loader_context_fds;
+        }
+
+        // program name, dex file, isa, filter
+        AddArg(dex_file_arg);
+        AddArg(isa_arg);
+        AddArg(compiler_filter_arg);
+        if (oat_fd >= 0) {
+            AddArg(oat_fd_arg);
+        }
+        if (vdex_fd >= 0) {
+            AddArg(vdex_fd_arg);
+        }
+        AddArg(zip_fd_arg);
+        if (profile_was_updated) {
+            AddArg(assume_profile_changed);
+        }
+        if (downgrade) {
+            AddArg(downgrade_flag);
+        }
+        if (class_loader_context != nullptr) {
+            AddArg(class_loader_context_arg);
+            if (!class_loader_context_fds.empty()) {
+                AddArg(class_loader_context_fds_arg);
+            }
+        }
+
+        PrepareArgs(dexoptanalyzer_bin);
     }
 
-    std::string dex_file_arg = "--dex-file=" + dex_file;
-    std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
-    std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
-    std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
-    std::string isa_arg = "--isa=" + instruction_set;
-    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;
-    }
+    // Dexoptanalyzer mode which flattens the given class loader context and
+    // prints a list of its dex files in that flattened order.
+    RunDexoptAnalyzer(const char* class_loader_context) {
+        CHECK(class_loader_context != nullptr);
 
-    // program name, dex file, isa, filter, the final NULL
-    const int argc = 6 +
-        (profile_was_updated ? 1 : 0) +
-        (vdex_fd >= 0 ? 1 : 0) +
-        (oat_fd >= 0 ? 1 : 0) +
-        (downgrade ? 1 : 0) +
-        (class_loader_context != nullptr ? 1 : 0);
-    const char* argv[argc];
-    int i = 0;
-    argv[i++] = dexoptanalyzer_bin;
-    argv[i++] = dex_file_arg.c_str();
-    argv[i++] = isa_arg.c_str();
-    argv[i++] = compiler_filter_arg.c_str();
-    if (oat_fd >= 0) {
-        argv[i++] = oat_fd_arg.c_str();
-    }
-    if (vdex_fd >= 0) {
-        argv[i++] = vdex_fd_arg.c_str();
-    }
-    argv[i++] = zip_fd_arg.c_str();
-    if (profile_was_updated) {
-        argv[i++] = assume_profile_changed;
-    }
-    if (downgrade) {
-        argv[i++] = downgrade_flag;
-    }
-    if (class_loader_context != nullptr) {
-        argv[i++] = class_loader_context_arg.c_str();
-    }
-    argv[i] = NULL;
+        // We always run the analyzer in the background job.
+        const char* dexoptanalyzer_bin = select_execution_binary(
+             kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
 
-    execv(dexoptanalyzer_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
-}
+        AddArg("--flatten-class-loader-context");
+        AddArg(std::string("--class-loader-context=") + class_loader_context);
+        PrepareArgs(dexoptanalyzer_bin);
+    }
+};
 
 // Prepares the oat dir for the secondary dex files.
 static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1691,15 +1653,12 @@
             *dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
         case 1:  // dexoptanalyzer: dex2oat_from_scratch
             *dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
-        case 5:  // dexoptanalyzer: dex2oat_for_bootimage_odex
+        case 4:  // dexoptanalyzer: dex2oat_for_bootimage_odex
             *dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
-        case 6:  // dexoptanalyzer: dex2oat_for_filter_odex
+        case 5:  // dexoptanalyzer: dex2oat_for_filter_odex
             *dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
-        case 7:  // dexoptanalyzer: dex2oat_for_relocation_odex
-            *dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
         case 2:  // dexoptanalyzer: dex2oat_for_bootimage_oat
         case 3:  // dexoptanalyzer: dex2oat_for_filter_oat
-        case 4:  // dexoptanalyzer: dex2oat_for_relocation_oat
             *error_msg = StringPrintf("Dexoptanalyzer return the status of an oat file."
                                       " Expected odex file status for secondary dex %s"
                                       " : dexoptanalyzer result=%d",
@@ -1814,6 +1773,95 @@
     return true;
 }
 
+static bool get_class_loader_context_dex_paths(const char* class_loader_context, int uid,
+        /* out */ std::vector<std::string>* context_dex_paths) {
+    if (class_loader_context == nullptr) {
+      return true;
+    }
+
+    LOG(DEBUG) << "Getting dex paths for context " << class_loader_context;
+
+    // Pipe to get the hash result back from our child process.
+    unique_fd pipe_read, pipe_write;
+    if (!Pipe(&pipe_read, &pipe_write)) {
+        PLOG(ERROR) << "Failed to create pipe";
+        return false;
+    }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        // child -- drop privileges before continuing.
+        drop_capabilities(uid);
+
+        // Route stdout to `pipe_write`
+        while ((dup2(pipe_write, STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+        pipe_write.reset();
+        pipe_read.reset();
+
+        RunDexoptAnalyzer run_dexopt_analyzer(class_loader_context);
+        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+    }
+
+    /* parent */
+    pipe_write.reset();
+
+    std::string str_dex_paths;
+    if (!ReadFdToString(pipe_read, &str_dex_paths)) {
+        PLOG(ERROR) << "Failed to read from pipe";
+        return false;
+    }
+    pipe_read.reset();
+
+    int return_code = wait_child(pid);
+    if (!WIFEXITED(return_code)) {
+        PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
+        return false;
+    }
+
+    constexpr int kFlattenClassLoaderContextSuccess = 50;
+    return_code = WEXITSTATUS(return_code);
+    if (return_code != kFlattenClassLoaderContextSuccess) {
+        LOG(ERROR) << "Dexoptanalyzer could not flatten class loader context, code=" << return_code;
+        return false;
+    }
+
+    if (!str_dex_paths.empty()) {
+        *context_dex_paths = android::base::Split(str_dex_paths, ":");
+    }
+    return true;
+}
+
+static int open_dex_paths(const std::vector<std::string>& dex_paths,
+        /* out */ std::vector<unique_fd>* zip_fds, /* out */ std::string* error_msg) {
+    for (const std::string& dex_path : dex_paths) {
+        zip_fds->emplace_back(open(dex_path.c_str(), O_RDONLY));
+        if (zip_fds->back().get() < 0) {
+            *error_msg = StringPrintf(
+                    "installd cannot open '%s' for input during dexopt", dex_path.c_str());
+            if (errno == ENOENT) {
+                return kSecondaryDexDexoptAnalyzerSkippedNoFile;
+            } else {
+                return kSecondaryDexDexoptAnalyzerSkippedOpenZip;
+            }
+        }
+    }
+    return 0;
+}
+
+static std::string join_fds(const std::vector<unique_fd>& fds) {
+    std::stringstream ss;
+    bool is_first = true;
+    for (const unique_fd& fd : fds) {
+        if (is_first) {
+            is_first = false;
+        } else {
+            ss << ":";
+        }
+        ss << fd.get();
+    }
+    return ss.str();
+}
+
 // Processes the dex_path as a secondary dex files and return true if the path dex file should
 // be compiled. Returns false for errors (logged) or true if the secondary dex path was process
 // successfully.
@@ -1825,7 +1873,7 @@
         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, bool downgrade, const char* class_loader_context,
-        /* out */ std::string* error_msg) {
+        const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
     LOG(DEBUG) << "Processing secondary dex path " << dex_path;
     int storage_flag;
     if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
@@ -1865,6 +1913,13 @@
             }
         }
 
+        // Open class loader context dex files.
+        std::vector<unique_fd> context_zip_fds;
+        int open_dex_paths_rc = open_dex_paths(context_dex_paths, &context_zip_fds, error_msg);
+        if (open_dex_paths_rc != 0) {
+            _exit(open_dex_paths_rc);
+        }
+
         // Prepare the oat directories.
         if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
             _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
@@ -1887,16 +1942,18 @@
                 /*is_secondary_dex*/true);
 
         // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
-        exec_dexoptanalyzer(dex_path,
-                            vdex_file_fd.get(),
-                            oat_file_fd.get(),
-                            zip_fd.get(),
-                            instruction_set,
-                            compiler_filter, profile_was_updated,
-                            downgrade,
-                            class_loader_context);
-        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
-        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+        // Note that we do not do it before the fork since opening the files is required to happen
+        // after forking.
+        RunDexoptAnalyzer run_dexopt_analyzer(dex_path,
+                                              vdex_file_fd.get(),
+                                              oat_file_fd.get(),
+                                              zip_fd.get(),
+                                              instruction_set,
+                                              compiler_filter, profile_was_updated,
+                                              downgrade,
+                                              class_loader_context,
+                                              join_fds(context_zip_fds));
+        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
@@ -1983,10 +2040,16 @@
 
     // Check if we're dealing with a secondary dex file and if we need to compile it.
     std::string oat_dir_str;
+    std::vector<std::string> context_dex_paths;
     if (is_secondary_dex) {
+        if (!get_class_loader_context_dex_paths(class_loader_context, uid, &context_dex_paths)) {
+            *error_msg = "Failed acquiring context dex paths";
+            return -1;  // We had an error, logged in the process method.
+        }
+
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                downgrade, class_loader_context, error_msg)) {
+                downgrade, class_loader_context, context_dex_paths, error_msg)) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
@@ -1998,7 +2061,7 @@
             return -1;  // We had an error, logged in the process method.
         }
     } else {
-        // Currently these flags are only use for secondary dex files.
+        // Currently these flags are only used for secondary dex files.
         // Verify that they are not set for primary apks.
         CHECK((dexopt_flags & DEXOPT_STORAGE_CE) == 0);
         CHECK((dexopt_flags & DEXOPT_STORAGE_DE) == 0);
@@ -2012,6 +2075,13 @@
         return -1;
     }
 
+    // Open class loader context dex files.
+    std::vector<unique_fd> context_input_fds;
+    if (open_dex_paths(context_dex_paths, &context_input_fds, error_msg) != 0) {
+        LOG(ERROR) << *error_msg;
+        return -1;
+    }
+
     // Create the output OAT file.
     char out_oat_path[PKG_PATH_MAX];
     Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
@@ -2065,6 +2135,28 @@
 
     LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
+    RunDex2Oat runner(input_fd.get(),
+                      out_oat_fd.get(),
+                      in_vdex_fd.get(),
+                      out_vdex_fd.get(),
+                      image_fd.get(),
+                      dex_path,
+                      out_oat_path,
+                      swap_fd.get(),
+                      instruction_set,
+                      compiler_filter,
+                      debuggable,
+                      boot_complete,
+                      background_job_compile,
+                      reference_profile_fd.get(),
+                      class_loader_context,
+                      join_fds(context_input_fds),
+                      target_sdk_version,
+                      enable_hidden_api_checks,
+                      generate_compact_dex,
+                      dex_metadata_fd.get(),
+                      compilation_reason);
+
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2076,26 +2168,7 @@
             _exit(DexoptReturnCodes::kFlock);
         }
 
-        run_dex2oat(input_fd.get(),
-                    out_oat_fd.get(),
-                    in_vdex_fd.get(),
-                    out_vdex_fd.get(),
-                    image_fd.get(),
-                    dex_path,
-                    out_oat_path,
-                    swap_fd.get(),
-                    instruction_set,
-                    compiler_filter,
-                    debuggable,
-                    boot_complete,
-                    background_job_compile,
-                    reference_profile_fd.get(),
-                    class_loader_context,
-                    target_sdk_version,
-                    enable_hidden_api_checks,
-                    generate_compact_dex,
-                    dex_metadata_fd.get(),
-                    compilation_reason);
+        runner.Exec(DexoptReturnCodes::kDex2oatExec);
     } else {
         int res = wait_child(pid);
         if (res == 0) {
@@ -2186,7 +2259,7 @@
         drop_capabilities(uid);
 
         const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
-        if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
                 uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
             _exit(kReconcileSecondaryDexValidationError);
@@ -2423,18 +2496,14 @@
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
     // Get the current slot suffix. No suffix, no A/B.
-    std::string slot_suffix;
-    {
-        char buf[kPropertyValueMax];
-        if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
-            return false;
-        }
-        slot_suffix = buf;
+    const std::string slot_suffix = GetProperty("ro.boot.slot_suffix", "");
+    if (slot_suffix.empty()) {
+        return false;
+    }
 
-        if (!ValidateTargetSlotSuffix(slot_suffix)) {
-            LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
-            return false;
-        }
+    if (!ValidateTargetSlotSuffix(slot_suffix)) {
+        LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+        return false;
     }
 
     // Validate other inputs.
@@ -2663,11 +2732,13 @@
         return false;
     }
 
+    RunProfman args;
+    args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
-        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+        args.Exec();
     }
 
     /* parent */
@@ -2691,6 +2762,13 @@
         return false;
     }
 
+    // Return false for empty class path since it may otherwise return true below if profiles is
+    // empty.
+    if (classpath.empty()) {
+        PLOG(ERROR) << "Class path is empty";
+        return false;
+    }
+
     // Open and create the snapshot profile.
     unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
 
@@ -2740,6 +2818,12 @@
                 profiles_fd.push_back(std::move(fd));
             }
         }
+        RunProfman args;
+        args.SetupMerge(profiles_fd,
+                        snapshot_fd,
+                        apk_fds,
+                        dex_locations,
+                        /*store_aggregation_counters=*/true);
         pid_t pid = fork();
         if (pid == 0) {
             /* child -- drop privileges before continuing */
@@ -2747,7 +2831,7 @@
 
             // The introduction of new access flags into boot jars causes them to
             // fail dex file verification.
-            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
+            args.Exec();
         }
 
         /* parent */
@@ -2801,6 +2885,11 @@
         return false;
     }
 
+    RunProfman args;
+    args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
+                            std::move(ref_profile_fd),
+                            std::move(apk_fd),
+                            code_path);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2808,10 +2897,7 @@
         drop_capabilities(app_shared_gid);
 
         // The copy and update takes ownership over the fds.
-        run_profman_copy_and_update(std::move(dex_metadata_fd),
-                                    std::move(ref_profile_fd),
-                                    std::move(apk_fd),
-                                    code_path);
+        args.Exec();
     }
 
     /* parent */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index bb6fab3..a8c48c5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -31,7 +31,16 @@
 static constexpr int DEX2OAT_FROM_SCRATCH        = 1;
 static constexpr int DEX2OAT_FOR_BOOT_IMAGE      = 2;
 static constexpr int DEX2OAT_FOR_FILTER          = 3;
-static constexpr int DEX2OAT_FOR_RELOCATION      = 4;
+
+#define ANDROID_RUNTIME_APEX_BIN "/apex/com.android.runtime/bin"
+// Location of binaries in the Android Runtime APEX.
+static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat";
+static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd";
+static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profman";
+static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer";
+static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd";
+#undef ANDROID_RUNTIME_APEX_BIN
 
 // Clear the reference profile identified by the given profile name.
 bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name);
@@ -119,6 +128,14 @@
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
 
+const char* select_execution_binary(
+        const char* binary,
+        const char* debug_binary,
+        bool background_job_compile,
+        bool is_debug_runtime,
+        bool is_release,
+        bool is_debuggable_build);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index b3a6daf..1394701 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -44,6 +44,8 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
+static constexpr const char* STAGING_SUBDIR = "app-staging/"; // sub-directory under ANDROID_DATA
+
 std::string android_app_dir;
 std::string android_app_ephemeral_dir;
 std::string android_app_lib_dir;
@@ -54,6 +56,7 @@
 std::string android_mnt_expand_dir;
 std::string android_profiles_dir;
 std::string android_root_dir;
+std::string android_staging_dir;
 
 std::vector<std::string> android_system_dirs;
 
@@ -110,6 +113,9 @@
     // Get the android profiles directory.
     android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
+    // Get the android session staging directory.
+    android_staging_dir = android_data_dir + STAGING_SUBDIR;
+
     // Take note of the system and vendor directories.
     android_system_dirs.clear();
     android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 633e33b..a88a86e 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -38,6 +38,7 @@
 extern std::string android_mnt_expand_dir;
 extern std::string android_profiles_dir;
 extern std::string android_root_dir;
+extern std::string android_staging_dir;
 
 extern std::vector<std::string> android_system_dirs;
 
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 95ed2ff..673ff0d 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -107,7 +107,7 @@
         DIR *dir;
         struct dirent *dirent;
         dir = opendir("/data/user");
-        if (dir != NULL) {
+        if (dir != nullptr) {
             while ((dirent = readdir(dir))) {
                 const char *name = dirent->d_name;
 
@@ -146,10 +146,10 @@
             closedir(dir);
 
             if (access(keychain_added_dir, F_OK) == 0) {
-                delete_dir_contents(keychain_added_dir, 1, 0);
+                delete_dir_contents(keychain_added_dir, 1, nullptr);
             }
             if (access(keychain_removed_dir, F_OK) == 0) {
-                delete_dir_contents(keychain_removed_dir, 1, 0);
+                delete_dir_contents(keychain_removed_dir, 1, nullptr);
             }
         }
 
diff --git a/cmds/installd/matchgen.py b/cmds/installd/matchgen.py
index 131487d..42ce82b 100644
--- a/cmds/installd/matchgen.py
+++ b/cmds/installd/matchgen.py
@@ -84,6 +84,8 @@
                 print "%scase '%s':" % (prefix, k)
             dump(target[k], index + 1)
     print "%s}" % (prefix)
+    if index > 0:
+        print "%sbreak;" % (prefix)
 
 dump(trie, 0)
 
diff --git a/cmds/installd/migrate_legacy_obb_data.sh b/cmds/installd/migrate_legacy_obb_data.sh
new file mode 100644
index 0000000..1075688
--- /dev/null
+++ b/cmds/installd/migrate_legacy_obb_data.sh
@@ -0,0 +1,40 @@
+#!/system/bin/sh
+
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+rm -rf /sdcard/Android/obb/test_probe
+mkdir -p /sdcard/Android/obb/
+touch /sdcard/Android/obb/test_probe
+if ! test -f /data/media/0/Android/obb/test_probe ; then
+  log -p i -t migrate_legacy_obb_data "No support for 'unshared_obb'. Not migrating"
+  rm -rf /sdcard/Android/obb/test_probe
+  exit 0
+fi
+
+# Delete the test file, and remove the obb folder if it is empty
+rm -rf /sdcard/Android/obb/test_probe
+rmdir /data/media/obb
+
+if ! test -d /data/media/obb ; then
+  log -p i -t migrate_legacy_obb_data "No legacy obb data to migrate."
+  exit 0
+fi
+
+log -p i -t migrate_legacy_obb_data "Migrating legacy obb data."
+rm -rf /data/media/0/Android/obb
+cp -F -p -R -P -d /data/media/obb /data/media/0/Android
+rm -rf /data/media/obb
+log -p i -t migrate_legacy_obb_data "Done."
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 96d8c47..de7b249 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,12 +26,12 @@
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <art_image_values.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <dex2oat_return_codes.h>
@@ -57,7 +57,6 @@
 #define REPLY_MAX     256   /* largest reply allowed */
 
 using android::base::EndsWith;
-using android::base::Join;
 using android::base::Split;
 using android::base::StartsWith;
 using android::base::StringPrintf;
@@ -88,6 +87,12 @@
               "DEXOPT_MASK unexpected.");
 
 
+template<typename T>
+static constexpr bool IsPowerOfTwo(T x) {
+  static_assert(std::is_integral<T>::value, "T must be integral");
+  // TODO: assert unsigned. There is currently many uses with signed values.
+  return (x & (x - 1)) == 0;
+}
 
 template<typename T>
 static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
@@ -315,21 +320,8 @@
             return false;
         }
         const char* isa = parameters_.instruction_set;
-
-        // Check whether the file exists where expected.
         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
         std::string isa_path = dalvik_cache + "/" + isa;
-        std::string art_path = isa_path + "/system@framework@boot.art";
-        std::string oat_path = isa_path + "/system@framework@boot.oat";
-        bool cleared = false;
-        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
-            // Files exist, assume everything is alright if not forced. Otherwise clean up.
-            if (!force) {
-                return true;
-            }
-            ClearDirectory(isa_path);
-            cleared = true;
-        }
 
         // Reset umask in otapreopt, so that we control the the access for the files we create.
         umask(0);
@@ -348,18 +340,34 @@
             }
         }
 
-        // Prepare to create.
+        // Check whether we have files in /data.
+        // TODO: check that the files are correct wrt/ jars.
+        std::string art_path = isa_path + "/system@framework@boot.art";
+        std::string oat_path = isa_path + "/system@framework@boot.oat";
+        bool cleared = false;
+        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
+            // Files exist, assume everything is alright if not forced. Otherwise clean up.
+            if (!force) {
+                return true;
+            }
+            ClearDirectory(isa_path);
+            cleared = true;
+        }
+
+        // Check whether we have an image in /system.
+        // TODO: check that the files are correct wrt/ jars.
+        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
+        if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
+            // Note: we ignore |force| here.
+            return true;
+        }
+
+
         if (!cleared) {
             ClearDirectory(isa_path);
         }
 
-        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
-        if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
-          return PatchoatBootImage(isa_path, isa);
-        } else {
-          // No preopted boot image. Try to compile.
-          return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
-        }
+        return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
     }
 
     static bool CreatePath(const std::string& path) {
@@ -424,45 +432,22 @@
         CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
     }
 
-    bool PatchoatBootImage(const std::string& output_dir, const char* isa) const {
-        // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
-
-        std::vector<std::string> cmd;
-        cmd.push_back("/system/bin/patchoat");
-
-        cmd.push_back("--input-image-location=/system/framework/boot.art");
-        cmd.push_back(StringPrintf("--output-image-directory=%s", output_dir.c_str()));
-
-        cmd.push_back(StringPrintf("--instruction-set=%s", isa));
-
-        int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
-                                                          ART_BASE_ADDRESS_MAX_DELTA);
-        cmd.push_back(StringPrintf("--base-offset-delta=%d", base_offset));
-
-        std::string error_msg;
-        bool result = Exec(cmd, &error_msg);
-        if (!result) {
-            LOG(ERROR) << "Could not generate boot image: " << error_msg;
-        }
-        return result;
-    }
-
     bool Dex2oatBootImage(const std::string& boot_cp,
                           const std::string& art_path,
                           const std::string& oat_path,
                           const char* isa) const {
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
         std::vector<std::string> cmd;
-        cmd.push_back("/system/bin/dex2oat");
+        cmd.push_back(kDex2oatPath);
         cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
         for (const std::string& boot_part : Split(boot_cp, ":")) {
             cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
         }
         cmd.push_back(StringPrintf("--oat-file=%s", oat_path.c_str()));
 
-        int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
-                ART_BASE_ADDRESS_MAX_DELTA);
-        cmd.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset));
+        int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(),
+                                                          art::GetImageMaxBaseAddressDelta());
+        cmd.push_back(StringPrintf("--base=0x%x", art::GetImageBaseAddress() + base_offset));
 
         cmd.push_back(StringPrintf("--instruction-set=%s", isa));
 
@@ -604,7 +589,7 @@
         // If the dexopt failed, we may have a stale boot image from a previous OTA run.
         // Then regenerate and retry.
         if (WEXITSTATUS(dexopt_result) ==
-                static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime)) {
+                static_cast<int>(::art::dex2oat::ReturnCode::kCreateRuntime)) {
             if (!PrepareBootImage(/* force */ true)) {
                 LOG(ERROR) << "Forced boot image creating failed. Original error return was "
                         << dexopt_result;
@@ -632,61 +617,6 @@
     // Helpers, mostly taken from ART //
     ////////////////////////////////////
 
-    // Wrapper on fork/execv to run a command in a subprocess.
-    static bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
-        const std::string command_line = Join(arg_vector, ' ');
-
-        CHECK_GE(arg_vector.size(), 1U) << command_line;
-
-        // Convert the args to char pointers.
-        const char* program = arg_vector[0].c_str();
-        std::vector<char*> args;
-        for (size_t i = 0; i < arg_vector.size(); ++i) {
-            const std::string& arg = arg_vector[i];
-            char* arg_str = const_cast<char*>(arg.c_str());
-            CHECK(arg_str != nullptr) << i;
-            args.push_back(arg_str);
-        }
-        args.push_back(nullptr);
-
-        // Fork and exec.
-        pid_t pid = fork();
-        if (pid == 0) {
-            // No allocation allowed between fork and exec.
-
-            // Change process groups, so we don't get reaped by ProcessManager.
-            setpgid(0, 0);
-
-            execv(program, &args[0]);
-
-            PLOG(ERROR) << "Failed to execv(" << command_line << ")";
-            // _exit to avoid atexit handlers in child.
-            _exit(1);
-        } else {
-            if (pid == -1) {
-                *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
-                        command_line.c_str(), strerror(errno));
-                return false;
-            }
-
-            // wait for subprocess to finish
-            int status;
-            pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
-            if (got_pid != pid) {
-                *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
-                        "wanted %d, got %d: %s",
-                        command_line.c_str(), pid, got_pid, strerror(errno));
-                return false;
-            }
-            if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-                *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
-                        command_line.c_str());
-                return false;
-            }
-        }
-        return true;
-    }
-
     // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
     static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
         constexpr size_t kPageSize = PAGE_SIZE;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index e90cf3b..2e2cc18 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <linux/unistd.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 
 #include <sstream>
@@ -24,6 +25,10 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <libdm/dm.h>
+#include <selinux/android.h>
+
+#include <apexd.h>
 
 #include "installd_constants.h"
 #include "otapreopt_utils.h"
@@ -54,6 +59,56 @@
     }
 }
 
+static std::vector<apex::ApexFile> ActivateApexPackages() {
+    // The logic here is (partially) copied and adapted from
+    // system/apex/apexd/apexd_main.cpp.
+    //
+    // Only scan the APEX directory under /system (within the chroot dir).
+    apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+    return apex::getActivePackages();
+}
+
+static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
+    for (const apex::ApexFile& apex_file : active_packages) {
+        const std::string& package_path = apex_file.GetPath();
+        apex::Status status = apex::deactivatePackage(package_path);
+        if (!status.Ok()) {
+            LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
+        }
+    }
+}
+
+static void TryExtraMount(const char* name, const char* slot, const char* target) {
+    std::string partition_name = StringPrintf("%s%s", name, slot);
+
+    // See whether update_engine mounted a logical partition.
+    {
+        auto& dm = dm::DeviceMapper::Instance();
+        if (dm.GetState(partition_name) != dm::DmDeviceState::INVALID) {
+            std::string path;
+            if (dm.GetDmDevicePathByName(partition_name, &path)) {
+                int mount_result = mount(path.c_str(),
+                                         target,
+                                         "ext4",
+                                         MS_RDONLY,
+                                         /* data */ nullptr);
+                if (mount_result == 0) {
+                    return;
+                }
+            }
+        }
+    }
+
+    // Fall back and attempt a direct mount.
+    std::string block_device = StringPrintf("/dev/block/by-name/%s", partition_name.c_str());
+    int mount_result = mount(block_device.c_str(),
+                             target,
+                             "ext4",
+                             MS_RDONLY,
+                             /* data */ nullptr);
+    UNUSED(mount_result);
+}
+
 // Entry for otapreopt_chroot. Expected parameters are:
 //   [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
 // The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -114,28 +169,48 @@
         LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
         exit(207);
     }
-    {
-      std::string vendor_partition = StringPrintf("/dev/block/by-name/vendor%s",
-                                                  arg[2]);
-      int vendor_result = mount(vendor_partition.c_str(),
-                                "/postinstall/vendor",
-                                "ext4",
-                                MS_RDONLY,
-                                /* data */ nullptr);
-      UNUSED(vendor_result);
-    }
+    TryExtraMount("vendor", arg[2], "/postinstall/vendor");
 
     // Try to mount the product partition. update_engine doesn't do this for us, but we
     // want it for product APKs. Same notes as vendor above.
-    {
-      std::string product_partition = StringPrintf("/dev/block/by-name/product%s",
-                                                   arg[2]);
-      int product_result = mount(product_partition.c_str(),
-                                 "/postinstall/product",
-                                 "ext4",
-                                 MS_RDONLY,
-                                 /* data */ nullptr);
-      UNUSED(product_result);
+    TryExtraMount("product", arg[2], "/postinstall/product");
+
+    // Setup APEX mount point and its security context.
+    static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
+    // The following logic is similar to the one in system/core/rootdir/init.rc:
+    //
+    //   mount tmpfs tmpfs /apex nodev noexec nosuid
+    //   chmod 0755 /apex
+    //   chown root root /apex
+    //   restorecon /apex
+    //
+    // except we perform the `restorecon` step just after mounting the tmpfs
+    // filesystem in /postinstall/apex, so that this directory is correctly
+    // labeled (with type `postinstall_apex_mnt_dir`) and may be manipulated in
+    // following operations (`chmod`, `chown`, etc.) following policies
+    // restricted to `postinstall_apex_mnt_dir`:
+    //
+    //   mount tmpfs tmpfs /postinstall/apex nodev noexec nosuid
+    //   restorecon /postinstall/apex
+    //   chmod 0755 /postinstall/apex
+    //   chown root root /postinstall/apex
+    //
+    if (mount("tmpfs", kPostinstallApexDir, "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
+        != 0) {
+        PLOG(ERROR) << "Failed to mount tmpfs in " << kPostinstallApexDir;
+        exit(209);
+    }
+    if (selinux_android_restorecon(kPostinstallApexDir, 0) < 0) {
+        PLOG(ERROR) << "Failed to restorecon " << kPostinstallApexDir;
+        exit(214);
+    }
+    if (chmod(kPostinstallApexDir, 0755) != 0) {
+        PLOG(ERROR) << "Failed to chmod " << kPostinstallApexDir << " to 0755";
+        exit(210);
+    }
+    if (chown(kPostinstallApexDir, 0, 0) != 0) {
+        PLOG(ERROR) << "Failed to chown " << kPostinstallApexDir << " to root:root";
+        exit(211);
     }
 
     // Chdir into /postinstall.
@@ -155,22 +230,38 @@
         exit(205);
     }
 
+    // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
+    // the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
+    std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
+
     // Now go on and run otapreopt.
 
-    // Incoming:  cmd + status-fd + target-slot + cmd... + null      | Incoming | = argc + 1
-    // Outgoing:  cmd             + target-slot + cmd... + null      | Outgoing | = argc
-    const char** argv = new const char*[argc];
-
-    argv[0] = "/system/bin/otapreopt";
+    // Incoming:  cmd + status-fd + target-slot + cmd...      | Incoming | = argc
+    // Outgoing:  cmd             + target-slot + cmd...      | Outgoing | = argc - 1
+    std::vector<std::string> cmd;
+    cmd.reserve(argc);
+    cmd.push_back("/system/bin/otapreopt");
 
     // The first parameter is the status file descriptor, skip.
-    for (size_t i = 2; i <= static_cast<size_t>(argc); ++i) {
-        argv[i - 1] = arg[i];
+    for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
+        cmd.push_back(arg[i]);
     }
 
-    execv(argv[0], static_cast<char * const *>(const_cast<char**>(argv)));
-    PLOG(ERROR) << "execv(OTAPREOPT) failed.";
-    exit(99);
+    // Fork and execute otapreopt in its own process.
+    std::string error_msg;
+    bool exec_result = Exec(cmd, &error_msg);
+    if (!exec_result) {
+        LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+    }
+
+    // Tear down the work down by the apexd logic. (i.e. deactivate packages).
+    DeactivateApexPackages(active_packages);
+
+    if (!exec_result) {
+        exit(213);
+    }
+
+    return 0;
 }
 
 }  // namespace installd
diff --git a/cmds/installd/otapreopt_parameters.cpp b/cmds/installd/otapreopt_parameters.cpp
index cf3de01..b1ad8db 100644
--- a/cmds/installd/otapreopt_parameters.cpp
+++ b/cmds/installd/otapreopt_parameters.cpp
@@ -16,6 +16,8 @@
 
 #include "otapreopt_parameters.h"
 
+#include <cstring>
+
 #include <android-base/logging.h>
 
 #include "dexopt.h"
@@ -248,6 +250,8 @@
         case 8: num_args_expected = 16; break;
         // Version 9 adds a new dexopt flag: DEXOPT_GENERATE_APP_IMAGE
         case 9: num_args_expected = 16; break;
+        // Version 10 is a compatibility bump.
+        case 10: num_args_expected = 16; break;
         default:
             LOG(ERROR) << "Don't know how to read arguments for version " << version;
             return false;
@@ -360,6 +364,15 @@
         }
     }
 
+    if (version < 10) {
+        // Do not accept '&' as shared libraries from versions prior to 10. These may lead
+        // to runtime crashes. The server side of version 10+ should send the correct
+        // context in almost all cases (e.g., only for actual shared packages).
+        if (shared_libraries != nullptr && std::string("&") == shared_libraries) {
+            return false;
+        }
+    }
+
     return true;
 }
 
diff --git a/cmds/installd/otapreopt_utils.cpp b/cmds/installd/otapreopt_utils.cpp
new file mode 100644
index 0000000..124f726
--- /dev/null
+++ b/cmds/installd/otapreopt_utils.cpp
@@ -0,0 +1,88 @@
+/*
+ ** Copyright 2019, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "otapreopt_utils.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+using android::base::Join;
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
+    const std::string command_line = Join(arg_vector, ' ');
+
+    CHECK_GE(arg_vector.size(), 1U) << command_line;
+
+    // Convert the args to char pointers.
+    const char* program = arg_vector[0].c_str();
+    std::vector<char*> args;
+    for (size_t i = 0; i < arg_vector.size(); ++i) {
+        const std::string& arg = arg_vector[i];
+        char* arg_str = const_cast<char*>(arg.c_str());
+        CHECK(arg_str != nullptr) << i;
+        args.push_back(arg_str);
+    }
+    args.push_back(nullptr);
+
+    // Fork and exec.
+    pid_t pid = fork();
+    if (pid == 0) {
+        // No allocation allowed between fork and exec.
+
+        // Change process groups, so we don't get reaped by ProcessManager.
+        setpgid(0, 0);
+
+        execv(program, &args[0]);
+
+        PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+        // _exit to avoid atexit handlers in child.
+        _exit(1);
+    } else {
+        if (pid == -1) {
+            *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
+                    command_line.c_str(), strerror(errno));
+            return false;
+        }
+
+        // wait for subprocess to finish
+        int status;
+        pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+        if (got_pid != pid) {
+            *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
+                    "wanted %d, got %d: %s",
+                    command_line.c_str(), pid, got_pid, strerror(errno));
+            return false;
+        }
+        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+            *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
+                    command_line.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/otapreopt_utils.h b/cmds/installd/otapreopt_utils.h
index 436e554..03a6d87 100644
--- a/cmds/installd/otapreopt_utils.h
+++ b/cmds/installd/otapreopt_utils.h
@@ -18,6 +18,8 @@
 #define OTAPREOPT_UTILS_H_
 
 #include <regex>
+#include <string>
+#include <vector>
 
 namespace android {
 namespace installd {
@@ -28,6 +30,9 @@
     return std::regex_match(input, slot_suffix_match, slot_suffix_regex);
 }
 
+// Wrapper on fork/execv to run a command in a subprocess.
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 7438d3d..aa79fdc 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,6 +1,7 @@
 // Build the unit tests for installd
 cc_test {
     name: "installd_utils_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_utils_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -14,10 +15,12 @@
         "libinstalld",
         "liblog",
     ],
+    test_config: "installd_utils_test.xml",
 }
 
 cc_test {
     name: "installd_cache_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_cache_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -26,8 +29,10 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -35,10 +40,12 @@
         "liblog",
         "liblogwrap",
     ],
+    test_config: "installd_cache_test.xml",
 }
 
 cc_test {
     name: "installd_service_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_service_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -47,8 +54,10 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -56,10 +65,12 @@
         "liblog",
         "liblogwrap",
     ],
+    test_config: "installd_service_test.xml",
 }
 
 cc_test {
     name: "installd_dexopt_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_dexopt_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -68,8 +79,10 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -77,10 +90,12 @@
         "liblog",
         "liblogwrap",
     ],
+    test_config: "installd_dexopt_test.xml",
 }
 
 cc_test {
     name: "installd_otapreopt_test",
+    test_suites: ["device-tests"],
     clang: true,
     srcs: ["installd_otapreopt_test.cpp"],
     cflags: ["-Wall", "-Werror"],
@@ -88,6 +103,7 @@
         "libbase",
         "libcutils",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "liblog",
diff --git a/cmds/installd/tests/binder_test_utils.h b/cmds/installd/tests/binder_test_utils.h
new file mode 100644
index 0000000..efd1391
--- /dev/null
+++ b/cmds/installd/tests/binder_test_utils.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+#define ASSERT_BINDER_SUCCESS(expr)                                              \
+    ({                                                                           \
+        binder::Status expect_status = (expr);                                   \
+        ASSERT_TRUE(expect_status.isOk()) << expect_status.toString8().c_str();  \
+        expect_status;                                                           \
+    })
+#define ASSERT_BINDER_FAIL(expr)                \
+    ({                                          \
+        binder::Status expect_status = (expr);  \
+        ASSERT_FALSE(expect_status.isOk());     \
+        expect_status;                          \
+    })
+#define EXPECT_BINDER_SUCCESS(expr)                                              \
+    ({                                                                           \
+        binder::Status expect_status = (expr);                                   \
+        EXPECT_TRUE(expect_status.isOk()) << expect_status.toString8().c_str();  \
+        expect_status;                                                           \
+    })
+#define EXPECT_BINDER_FAIL(expr)                \
+    ({                                          \
+        binder::Status expect_status = (expr);  \
+        EXPECT_FALSE(expect_status.isOk());     \
+        expect_status;                          \
+    })
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 2d58515..db09070 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -40,8 +40,8 @@
 constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
 constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
 
-static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+#define FLAG_FREE_CACHE_V2 InstalldNativeService::FLAG_FREE_CACHE_V2
+#define FLAG_FREE_CACHE_V2_DEFY_QUOTA InstalldNativeService::FLAG_FREE_CACHE_V2_DEFY_QUOTA
 
 int get_property(const char *key, char *value, const char *default_value) {
     return property_get(key, value, default_value);
diff --git a/cmds/installd/tests/installd_cache_test.xml b/cmds/installd/tests/installd_cache_test.xml
new file mode 100644
index 0000000..97af514
--- /dev/null
+++ b/cmds/installd/tests/installd_cache_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_cache_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_cache_test->/data/local/tmp/installd_cache_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_cache_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 279bce8..fa2b0d9 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -23,9 +23,11 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
-
+#include <binder/Status.h>
 #include <cutils/properties.h>
 
 #include <gtest/gtest.h>
@@ -33,6 +35,7 @@
 #include <selinux/android.h>
 #include <selinux/avc.h>
 
+#include "binder_test_utils.h"
 #include "dexopt.h"
 #include "InstalldNativeService.h"
 #include "globals.h"
@@ -84,10 +87,33 @@
     system(cmd.c_str());
 }
 
-static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
-    ::mkdir(path.c_str(), mode);
-    ::chown(path.c_str(), owner, group);
-    ::chmod(path.c_str(), mode);
+template <typename Visitor>
+static void run_cmd_and_process_output(const std::string& cmd, const Visitor& visitor) {
+    FILE* file = popen(cmd.c_str(), "r");
+    CHECK(file != nullptr) << "Failed to ptrace " << cmd;
+    char* line = nullptr;
+    while (true) {
+        size_t n = 0u;
+        ssize_t value = getline(&line, &n, file);
+        if (value == -1) {
+            break;
+        }
+        visitor(line);
+    }
+    free(line);
+    fclose(file);
+}
+
+static int mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+    int ret = ::mkdir(path.c_str(), mode);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = ::chown(path.c_str(), owner, group);
+    if (ret != 0) {
+        return ret;
+    }
+    return ::chmod(path.c_str(), mode);
 }
 
 static int log_callback(int type, const char *fmt, ...) { // NOLINT
@@ -137,6 +163,20 @@
     "AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns"
     "+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA";
 
+class DexoptTestEnvTest : public testing::Test {
+};
+
+TEST_F(DexoptTestEnvTest, CheckSelinux) {
+    ASSERT_EQ(1, is_selinux_enabled());
+
+    // Crude cutout for virtual devices.
+#if !defined(__i386__) && !defined(__x86_64__)
+    constexpr bool kIsX86 = false;
+#else
+    constexpr bool kIsX86 = true;
+#endif
+    ASSERT_TRUE(1 == security_getenforce() || kIsX86 || true /* b/119032200 */);
+}
 
 class DexoptTest : public testing::Test {
 protected:
@@ -184,7 +224,7 @@
         se_info_ = "default";
         app_apk_dir_ = android_app_dir + package_name_;
 
-        create_mock_app();
+        ASSERT_TRUE(create_mock_app());
     }
 
     virtual void TearDown() {
@@ -198,33 +238,57 @@
         delete service_;
     }
 
-    void create_mock_app() {
+    ::testing::AssertionResult create_mock_app() {
         // Create the oat dir.
         app_oat_dir_ = app_apk_dir_ + "/oat";
-        mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755);
-        service_->createOatDir(app_oat_dir_, kRuntimeIsa);
+        // For debug mode, the directory might already exist. Avoid erroring out.
+        if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) {
+            return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_
+                                                 << " : " << strerror(errno);
+        }
+        binder::Status status = service_->createOatDir(app_oat_dir_, kRuntimeIsa);
+        if (!status.isOk()) {
+            return ::testing::AssertionFailure() << "Could not create oat dir: "
+                                                 << status.toString8().c_str();
+        }
 
         // Copy the primary apk.
         apk_path_ = app_apk_dir_ + "/base.jar";
-        ASSERT_TRUE(WriteBase64ToFile(kDexFile, apk_path_, kSystemUid, kSystemGid, 0644));
+        std::string error_msg;
+        if (!WriteBase64ToFile(kDexFile, apk_path_, kSystemUid, kSystemGid, 0644, &error_msg)) {
+            return ::testing::AssertionFailure() << "Could not write base64 file to " << apk_path_
+                                                 << " : " << error_msg;
+        }
 
         // Create the app user data.
-        ASSERT_TRUE(service_->createAppData(
-            volume_uuid_,
-            package_name_,
-            kTestUserId,
-            kAppDataFlags,
-            kTestAppUid,
-            se_info_,
-            kOSdkVersion,
-            &ce_data_inode_).isOk());
+        status = service_->createAppData(
+                volume_uuid_,
+                package_name_,
+                kTestUserId,
+                kAppDataFlags,
+                kTestAppUid,
+                se_info_,
+                kOSdkVersion,
+                &ce_data_inode_);
+        if (!status.isOk()) {
+            return ::testing::AssertionFailure() << "Could not create app data: "
+                                                 << status.toString8().c_str();
+        }
 
         // Create a secondary dex file on CE storage
         const char* volume_uuid_cstr = volume_uuid_ == nullptr ? nullptr : volume_uuid_->c_str();
         app_private_dir_ce_ = create_data_user_ce_package_path(
                 volume_uuid_cstr, kTestUserId, package_name_.c_str());
         secondary_dex_ce_ = app_private_dir_ce_ + "/secondary_ce.jar";
-        ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_ce_, kTestAppUid, kTestAppGid, 0600));
+        if (!WriteBase64ToFile(kDexFile,
+                               secondary_dex_ce_,
+                               kTestAppUid,
+                               kTestAppGid,
+                               0600,
+                               &error_msg)) {
+            return ::testing::AssertionFailure() << "Could not write base64 file to "
+                                                 << secondary_dex_ce_ << " : " << error_msg;
+        }
         std::string app_private_dir_ce_link = create_data_user_ce_package_path_as_user_link(
                 volume_uuid_cstr, kTestUserId, package_name_.c_str());
         secondary_dex_ce_link_ = app_private_dir_ce_link + "/secondary_ce.jar";
@@ -233,10 +297,24 @@
         app_private_dir_de_ = create_data_user_de_package_path(
                 volume_uuid_cstr, kTestUserId, package_name_.c_str());
         secondary_dex_de_ = app_private_dir_de_ + "/secondary_de.jar";
-        ASSERT_TRUE(WriteBase64ToFile(kDexFile, secondary_dex_de_, kTestAppUid, kTestAppGid, 0600));
+        if (!WriteBase64ToFile(kDexFile,
+                               secondary_dex_de_,
+                               kTestAppUid,
+                               kTestAppGid,
+                               0600,
+                               &error_msg)) {
+            return ::testing::AssertionFailure() << "Could not write base64 file to "
+                                                 << secondary_dex_de_ << " : " << error_msg;
+        }
 
         // Fix app data uid.
-        ASSERT_TRUE(service_->fixupAppData(volume_uuid_, kTestUserId).isOk());
+        status = service_->fixupAppData(volume_uuid_, kTestUserId);
+        if (!status.isOk()) {
+            return ::testing::AssertionFailure() << "Could not fixup app data: "
+                                                 << status.toString8().c_str();
+        }
+
+        return ::testing::AssertionSuccess();
     }
 
 
@@ -249,16 +327,21 @@
 
     void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
             bool should_binder_call_succeed, bool should_dex_be_compiled = true,
-            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
+            /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1,
+            const char* class_loader_context = nullptr) {
         if (uid == -1) {
             uid = kTestAppUid;
         }
+        if (class_loader_context == nullptr) {
+            class_loader_context = "&";
+        }
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
         int32_t dexopt_needed = 0;  // does not matter;
         std::unique_ptr<std::string> out_path = nullptr;  // does not matter
         int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
         std::string compiler_filter = "speed-profile";
-        std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
+        std::unique_ptr<std::string> class_loader_context_ptr(
+                new std::string(class_loader_context));
         std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         bool downgrade = false;
         int32_t target_sdk_version = 0;  // default
@@ -394,11 +477,9 @@
         std::unique_ptr<std::string> compilation_reason_ptr(new std::string("test-reason"));
 
         bool prof_result;
-        binder::Status prof_binder_result = service_->prepareAppProfile(
+        ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
                 package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_,
-                /*dex_metadata*/ nullptr, &prof_result);
-
-        ASSERT_TRUE(prof_binder_result.isOk()) << prof_binder_result.toString8().c_str();
+                /*dex_metadata*/ nullptr, &prof_result));
         ASSERT_TRUE(prof_result);
 
         binder::Status result = service_->dexopt(apk_path_,
@@ -479,12 +560,26 @@
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
+TEST_F(DexoptTest, DexoptSecondaryCeWithContext) {
+    LOG(INFO) << "DexoptSecondaryCeWithContext";
+    std::string class_loader_context = "PCL[" + secondary_dex_ce_ + "]";
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+        /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
+}
+
 TEST_F(DexoptTest, DexoptSecondaryDe) {
     LOG(INFO) << "DexoptSecondaryDe";
     CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
+TEST_F(DexoptTest, DexoptSecondaryDeWithContext) {
+    LOG(INFO) << "DexoptSecondaryDeWithContext";
+    std::string class_loader_context = "PCL[" + secondary_dex_de_ + "]";
+    CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+        /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
+}
+
 TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
     LOG(INFO) << "DexoptSecondaryDoesNotExist";
     // If the file validates but does not exist we do not treat it as an error.
@@ -500,7 +595,7 @@
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status);
     EXPECT_STREQ(status.toString8().c_str(),
-                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+                 "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
@@ -509,7 +604,7 @@
     CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status);
     EXPECT_STREQ(status.toString8().c_str(),
-                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+                 "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
@@ -517,7 +612,8 @@
     binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status, kSystemUid);
-    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer open zip failed'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryPublic) {
@@ -539,7 +635,7 @@
                           DEX2OAT_FROM_SCRATCH,
                           &status);
     EXPECT_STREQ(status.toString8().c_str(),
-                 "Status(-8): \'256: Dex2oat invocation for "
+                 "Status(-8, EX_SERVICE_SPECIFIC): \'256: Dex2oat invocation for "
                  "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
 }
 
@@ -572,6 +668,50 @@
                         DEX2OAT_FROM_SCRATCH);
 }
 
+TEST_F(DexoptTest, ResolveStartupConstStrings) {
+    LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
+    const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";
+    const std::string previous_value = android::base::GetProperty(property, "");
+    auto restore_property = android::base::make_scope_guard([=]() {
+        android::base::SetProperty(property, previous_value);
+    });
+    std::string odex = GetPrimaryDexArtifact(app_oat_dir_.c_str(), apk_path_, "odex");
+    // Disable the property to start.
+    bool found_disable = false;
+    ASSERT_TRUE(android::base::SetProperty(property, "false")) << property;
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+                                DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+    run_cmd_and_process_output(
+            "oatdump --header-only --oat-file=" + odex,
+            [&](const std::string& line) {
+        if (line.find("--resolve-startup-const-strings=false") != std::string::npos) {
+            found_disable = true;
+        }
+    });
+    EXPECT_TRUE(found_disable);
+    // Enable the property and inspect that .art artifact is larger.
+    bool found_enable = false;
+    ASSERT_TRUE(android::base::SetProperty(property, "true")) << property;
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+                                DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+    run_cmd_and_process_output(
+            "oatdump --header-only --oat-file=" + odex,
+            [&](const std::string& line) {
+        if (line.find("--resolve-startup-const-strings=true") != std::string::npos) {
+            found_enable = true;
+        }
+    });
+    EXPECT_TRUE(found_enable);
+}
+
 class PrimaryDexReCompilationTest : public DexoptTest {
   public:
     virtual void SetUp() {
@@ -703,9 +843,8 @@
     void createProfileSnapshot(int32_t appid, const std::string& package_name,
             bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->createProfileSnapshot(
-                appid, package_name, kPrimaryProfile, apk_path_, &result);
-        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_BINDER_SUCCESS(service_->createProfileSnapshot(
+                appid, package_name, kPrimaryProfile, apk_path_, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -745,9 +884,8 @@
                               const std::string& code_path,
                               bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->mergeProfiles(
-                kTestAppUid, package_name, code_path, &result);
-        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_BINDER_SUCCESS(service_->mergeProfiles(
+                kTestAppUid, package_name, code_path, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -773,10 +911,9 @@
     void preparePackageProfile(const std::string& package_name, const std::string& profile_name,
             bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->prepareAppProfile(
+        ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
                 package_name, kTestUserId, kTestAppId, profile_name, apk_path_,
-                /*dex_metadata*/ nullptr, &result);
-        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+                /*dex_metadata*/ nullptr, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -799,8 +936,7 @@
   protected:
     void TransitionToSystemServer() {
         ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid));
-        int32_t res = selinux_android_setcontext(
-                kSystemUid, true, se_info_.c_str(), "system_server");
+        int32_t res = selinux_android_setcon("u:r:system_server:s0");
         ASSERT_EQ(0, res) << "Failed to setcon " << strerror(errno);
     }
 
@@ -862,8 +998,7 @@
     SetupProfiles(/*setup_ref*/ true);
     createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
 
-    binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, kPrimaryProfile);
-    ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+    ASSERT_BINDER_SUCCESS(service_->destroyProfileSnapshot(package_name_, kPrimaryProfile));
     struct stat st;
     ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st));
     ASSERT_EQ(ENOENT, errno);
@@ -921,7 +1056,7 @@
     ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
 
     // Run createAppData again which will offer to fix-up the profile directories.
-    ASSERT_TRUE(service_->createAppData(
+    ASSERT_BINDER_SUCCESS(service_->createAppData(
             volume_uuid_,
             package_name_,
             kTestUserId,
@@ -929,7 +1064,7 @@
             kTestAppUid,
             se_info_,
             kOSdkVersion,
-            &ce_data_inode_).isOk());
+            &ce_data_inode_));
 
     // Check the file access.
     CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
@@ -975,9 +1110,8 @@
 
     void createBootImageProfileSnapshot(const std::string& classpath, bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->createProfileSnapshot(
-                -1, "android", "android.prof", classpath, &result);
-        ASSERT_TRUE(binder_result.isOk());
+        ASSERT_BINDER_SUCCESS(service_->createProfileSnapshot(
+                -1, "android", "android.prof", classpath, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -1060,5 +1194,64 @@
     ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), ref_prof) != profiles.end());
 }
 
+TEST_F(DexoptTest, select_execution_binary) {
+    LOG(INFO) << "DexoptTestselect_execution_binary";
+
+    std::string release_str = app_private_dir_ce_  + "/release";
+    std::string debug_str = app_private_dir_ce_  + "/debug";
+
+    // Setup the binaries. Note that we only need executable files to actually
+    // test the execution binary selection
+    run_cmd("touch " + release_str);
+    run_cmd("touch " + debug_str);
+    run_cmd("chmod 777 " + release_str);
+    run_cmd("chmod 777 " + debug_str);
+
+    const char* release = release_str.c_str();
+    const char* debug = debug_str.c_str();
+
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ true,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ true,
+        /*is_debuggable_build=*/ true));
+
+    ASSERT_STREQ(debug, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ true,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+
+    ASSERT_STREQ(debug, select_execution_binary(
+        release,
+        debug,
+        /*background_job_compile=*/ true,
+        /*is_debug_runtime=*/ false,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ true));
+
+
+    // Select the release when the debug file is not there.
+    ASSERT_STREQ(release, select_execution_binary(
+        release,
+        "does_not_exist",
+        /*background_job_compile=*/ false,
+        /*is_debug_runtime=*/ true,
+        /*is_release=*/ false,
+        /*is_debuggable_build=*/ false));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_dexopt_test.xml b/cmds/installd/tests/installd_dexopt_test.xml
new file mode 100644
index 0000000..24526cc
--- /dev/null
+++ b/cmds/installd/tests/installd_dexopt_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_dexopt_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_dexopt_test->/data/local/tmp/installd_dexopt_test" />
+    </target_preparer>
+
+    <!-- The test runs as root to prepare the temporary directory, make selinux adjustments
+         and so on. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_dexopt_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_otapreopt_test.cpp b/cmds/installd/tests/installd_otapreopt_test.cpp
index b518507..66dd51e 100644
--- a/cmds/installd/tests/installd_otapreopt_test.cpp
+++ b/cmds/installd/tests/installd_otapreopt_test.cpp
@@ -114,11 +114,14 @@
             case 7: return "7";
             case 8: return "8";
             case 9: return "9";
+            case 10: return "10";
         }
         return nullptr;
     }
 
-    std::vector<const char*> getArgs(uint32_t version, bool versioned) {
+    std::vector<const char*> getArgs(uint32_t version,
+                                     bool versioned,
+                                     const char* shared_libs = "shared.lib") {
         std::vector<const char*> args;
         args.push_back("otapreopt");  // "otapreopt"
         args.push_back("a");  // slot
@@ -135,7 +138,7 @@
         args.push_back("0");  // dexopt_flags
         args.push_back("speed");  // filter
         args.push_back("!");  // volume
-        args.push_back("shared.lib");  // libs
+        args.push_back(shared_libs);  // libs
 
         if (version > 1) {
             args.push_back("!");  // seinfo
@@ -159,9 +162,11 @@
         return args;
     }
 
-    void VerifyReadArguments(uint32_t version, bool versioned) {
+    void VerifyReadArguments(uint32_t version,
+                             bool versioned,
+                             const char* shared_libs = "shared.lib") {
         OTAPreoptParameters params;
-        std::vector<const char*> args = getArgs(version, versioned);
+        std::vector<const char*> args = getArgs(version, versioned, shared_libs);
         ASSERT_TRUE(params.ReadArguments(args.size() - 1, args.data()));
         verifyPackageParameters(params, version, versioned, args.data());
     }
@@ -199,6 +204,18 @@
     VerifyReadArguments(7, true);
 }
 
+TEST_F(OTAPreoptTest, ReadArgumentsV9SharedLibsAmpersand) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(9, true, "&");
+    ASSERT_FALSE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
+TEST_F(OTAPreoptTest, ReadArgumentsV10SharedLibsAmpersand) {
+    OTAPreoptParameters params;
+    std::vector<const char*> args = getArgs(10, true, "&");
+    ASSERT_TRUE(params.ReadArguments(args.size() - 1, args.data()));
+}
+
 TEST_F(OTAPreoptTest, ReadArgumentsFailToManyArgs) {
     OTAPreoptParameters params;
     std::vector<const char*> args = getArgs(5, true);
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index a5af5d7..a31d510 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -15,16 +15,24 @@
  */
 
 #include <sstream>
+#include <string>
+
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/statvfs.h>
+#include <sys/stat.h>
 #include <sys/xattr.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 
+#include "binder_test_utils.h"
 #include "InstalldNativeService.h"
 #include "dexopt.h"
 #include "globals.h"
@@ -37,7 +45,7 @@
 
 constexpr const char* kTestUuid = "TEST";
 
-static constexpr int FLAG_FORCE = 1 << 16;
+#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
 
 int get_property(const char *key, char *value, const char *default_value) {
     return property_get(key, value, default_value);
@@ -63,27 +71,28 @@
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
     const std::string fullPath = get_full_path(path);
-    ::mkdir(fullPath.c_str(), mode);
-    ::chown(fullPath.c_str(), owner, group);
-    ::chmod(fullPath.c_str(), mode);
+    EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
+    EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
+    EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
 }
 
 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
     int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
-    ::fchown(fd, owner, group);
-    ::fchmod(fd, mode);
-    ::close(fd);
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(::fchown(fd, owner, group), 0);
+    EXPECT_EQ(::fchmod(fd, mode), 0);
+    EXPECT_EQ(::close(fd), 0);
 }
 
 static int stat_gid(const char* path) {
     struct stat buf;
-    ::stat(get_full_path(path).c_str(), &buf);
+    EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
     return buf.st_gid;
 }
 
 static int stat_mode(const char* path) {
     struct stat buf;
-    ::stat(get_full_path(path).c_str(), &buf);
+    EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
@@ -162,8 +171,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_TRUE(service->hashSecondaryDexFile(
-        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
     EXPECT_EQ(result.size(), 32U);
 
@@ -182,8 +191,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_TRUE(service->hashSecondaryDexFile(
-        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
     EXPECT_EQ(result.size(), 0U);
 }
@@ -197,8 +206,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_TRUE(service->hashSecondaryDexFile(
-        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
     EXPECT_EQ(result.size(), 0U);
 }
@@ -212,8 +221,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_FALSE(service->hashSecondaryDexFile(
-        dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
+        dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
 }
 
 TEST_F(ServiceTest, CalculateOat) {
@@ -240,5 +249,410 @@
     EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
 
+static bool mkdirs(const std::string& path, mode_t mode) {
+    struct stat sb;
+    if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
+        return true;
+    }
+
+    if (!mkdirs(android::base::Dirname(path), mode)) {
+        return false;
+    }
+
+    if (::mkdir(path.c_str(), mode) != 0) {
+        PLOG(DEBUG) << "Failed to create folder " << path;
+        return false;
+    }
+    return true;
+}
+
+class AppDataSnapshotTest : public testing::Test {
+private:
+    std::string rollback_ce_base_dir;
+    std::string rollback_de_base_dir;
+
+protected:
+    InstalldNativeService* service;
+
+    std::string fake_package_ce_path;
+    std::string fake_package_de_path;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        service = new InstalldNativeService();
+        ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+
+        init_globals_from_data_and_root();
+
+        rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0);
+        rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0);
+
+        fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+        fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+        ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700));
+        ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700));
+        ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700));
+        ASSERT_TRUE(mkdirs(fake_package_de_path, 0700));
+    }
+
+    virtual void TearDown() {
+        ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true));
+        ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true));
+        ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true));
+        ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true));
+
+        delete service;
+        ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true));
+    }
+};
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37);
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request a snapshot of the CE content but not the DE content.
+  int64_t ce_snapshot_inode;
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
+  struct stat buf;
+  memset(&buf, 0, sizeof(buf));
+  ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
+  ASSERT_EQ(ce_snapshot_inode, (int64_t) buf.st_ino);
+
+  std::string ce_content, de_content;
+  // At this point, we should have the CE content but not the DE content.
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_FALSE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", ce_content);
+
+  // Modify the CE content, so we can assert later that it's reflected
+  // in the snapshot.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE_MODIFIED", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request a snapshot of the DE content but not the CE content.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
+  // Only DE content snapshot was requested.
+  ASSERT_EQ(ce_snapshot_inode, 0);
+
+  // At this point, both the CE as well as the DE content should be fully
+  // populated.
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE", de_content);
+
+  // Modify the DE content, so we can assert later that it's reflected
+  // in our final snapshot.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE_MODIFIED", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request a snapshot of both the CE as well as the DE content.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE_MODIFIED", ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67);
+
+  auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar");
+  auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar");
+
+  // Since this test sets up data for another package, some bookkeeping is required.
+  auto deleter = [&]() {
+      ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true));
+      ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true));
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700));
+  ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700));
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request snapshot for the package com.foo.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+  // Now request snapshot with the same id for the package com.bar
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  // Check that both snapshots have correct data in them.
+  std::string com_foo_ce_content, com_foo_de_content;
+  std::string com_bar_ce_content, com_bar_de_content;
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content);
+  ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content);
+  ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73);
+
+  // Similuating app data absence.
+  ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true));
+  ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
+
+  int64_t ce_snapshot_inode;
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
+  // No CE content snapshot was performed.
+  ASSERT_EQ(ce_snapshot_inode, 0);
+
+  // The snapshot calls must succeed but there should be no snapshot
+  // created.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo");
+  auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo");
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
+
+  // Simulate presence of an existing snapshot
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", rollback_ce_dir + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", rollback_de_dir + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Create app data.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_2_CE", fake_package_ce_path + "/file2",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_2_DE", fake_package_de_path + "/file2",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  // Previous snapshot (with data for file1) must be cleared.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb));
+  // New snapshot (with data for file2) must be present.
+  ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb));
+  ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb));
+}
+
+TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) {
+  // Setup rollback folders to make sure that fails due to wrong volumeUuid being
+  // passed, not because of some other reason.
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
+
+  EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
+          "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) {
+  auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
+  auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
+  auto fake_package_de_cache_path = fake_package_de_path + "/cache";
+  auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700));
+  ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700));
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_code_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
+  // The snapshot call must clear cache.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((fake_package_ce_code_cache_path + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((fake_package_de_cache_path + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
+}
+
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
+
+  // Write contents to the rollback location. We'll write the same files to the
+  // app data location and make sure the restore has overwritten them.
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+
+  std::string ce_content, de_content;
+  ASSERT_TRUE(android::base::ReadFileToString(
+      fake_package_ce_path + "/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      fake_package_de_path + "/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("CE_RESTORE_CONTENT", ce_content);
+  ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57);
+
+  // Prepare data for snapshot.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  int64_t ce_snapshot_inode;
+  // Request a snapshot of both the CE as well as the DE content.
+  ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+  // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
+  ASSERT_NE(0, ce_snapshot_inode);
+  // Check snapshot is there.
+  struct stat sb;
+  ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+  // Check snapshot is deleted.
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+}
+
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543);
+
+  // Create a snapshot
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+
+  // Check snapshot is deleted.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+  // Check that deleting already deleted snapshot is no-op.
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+}
+
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+  // Setup rollback data to make sure that test fails due to wrong volumeUuid
+  // being passed, not because of some other reason.
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
+
+  ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
+          "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
+}
+
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
+  // Setup rollback data to make sure that fails due to wrong volumeUuid being
+  // passed, not because of some other reason.
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
+
+  EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
+          "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_service_test.xml b/cmds/installd/tests/installd_service_test.xml
new file mode 100644
index 0000000..b838f4f
--- /dev/null
+++ b/cmds/installd/tests/installd_service_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_service_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_service_test->/data/local/tmp/installd_service_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access. -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_service_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index bcdd03e..e61eb6e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -18,9 +18,11 @@
 #include <string.h>
 
 #include <android-base/logging.h>
+#include <android-base/scopeguard.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
+#include "MatchExtensionGen.h"
 #include "globals.h"
 #include "utils.h"
 
@@ -529,5 +531,102 @@
     EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
 }
 
+TEST_F(UtilsTest, MatchExtension_Valid) {
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("mpg"));
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("mpeg"));
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("mPeG"));
+    EXPECT_EQ(AID_MEDIA_VIDEO, MatchExtension("MPEG"));
+}
+
+TEST_F(UtilsTest, MatchExtension_Invalid) {
+    EXPECT_EQ(0, MatchExtension("log"));
+    EXPECT_EQ(0, MatchExtension("3amp"));
+    EXPECT_EQ(0, MatchExtension("fpe"));
+    EXPECT_EQ(0, MatchExtension("docx"));
+}
+
+TEST_F(UtilsTest, TestRollbackPaths) {
+    EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/10/rollback/37/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 10, 37, "com.foo"));
+
+    EXPECT_EQ("/data/misc_de/0/rollback/73/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 0, 73, "com.foo"));
+    EXPECT_EQ("/data/misc_de/10/rollback/13/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 10, 13, "com.foo"));
+
+    EXPECT_EQ("/data/misc_ce/0/rollback/57",
+            create_data_misc_ce_rollback_path(nullptr, 0, 57));
+    EXPECT_EQ("/data/misc_ce/10/rollback/1543",
+            create_data_misc_ce_rollback_path(nullptr, 10, 1543));
+
+    EXPECT_EQ("/data/misc_de/0/rollback/43",
+            create_data_misc_de_rollback_path(nullptr, 0, 43));
+    EXPECT_EQ("/data/misc_de/10/rollback/41",
+            create_data_misc_de_rollback_path(nullptr, 10, 41));
+
+    EXPECT_EQ("/data/misc_ce/0/rollback/17/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 17, "com.foo", 0));
+    EXPECT_EQ("/data/misc_ce/0/rollback/19/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 19, "com.foo", 239));
+
+    auto rollback_ce_path = create_data_misc_ce_rollback_path(nullptr, 0, 53);
+    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, 53,
+            "com.foo");
+    auto deleter = [&rollback_ce_path]() {
+        delete_dir_contents_and_dir(rollback_ce_path, true /* ignore_if_missing */);
+    };
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    EXPECT_NE(-1, mkdir(rollback_ce_path.c_str(), 700));
+    EXPECT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+
+    ino_t ce_data_inode;
+    EXPECT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+
+    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.foo", ce_data_inode));
+    // Check that path defined by inode is picked even if it's not the same as
+    // the fallback one.
+    EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.bar", ce_data_inode));
+
+    // These last couple of cases are never exercised in production because we
+    // only snapshot apps in the primary data partition. Exercise them here for
+    // the sake of completeness.
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/7/com.example",
+            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 7,
+                    "com.example"));
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/11/com.example",
+            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 11,
+                    "com.example"));
+}
+
+TEST_F(UtilsTest, TestCreateDirIfNeeded) {
+    system("mkdir -p /data/local/tmp/user/0");
+
+    auto deleter = [&]() {
+        delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+    };
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    // Create folder and check it's permissions.
+    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+    struct stat st;
+    ASSERT_EQ(0, stat("/data/local/tmp/user/0/foo", &st));
+    ASSERT_EQ(0700, st.st_mode & ALLPERMS);
+
+    // Check that create_dir_if_needed is no-op if folder already exists with
+    // correct permissions.
+    ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+
+    // Check -1 is returned if folder exists but with different permissions.
+    ASSERT_EQ(-1, create_dir_if_needed("/data/local/tmp/user/0/foo", 0750));
+
+    // Check that call fails if parent doesn't exist.
+    ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.xml b/cmds/installd/tests/installd_utils_test.xml
new file mode 100644
index 0000000..92aba50
--- /dev/null
+++ b/cmds/installd/tests/installd_utils_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+           root support. -->
+<configuration description="Runs installd_utils_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="installd_utils_test->/data/local/tmp/installd_utils_test" />
+    </target_preparer>
+
+    <!-- The test requires root for file access (rollback paths). -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="installd_utils_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
index b8785c6..70eefe2 100644
--- a/cmds/installd/tests/test_utils.h
+++ b/cmds/installd/tests/test_utils.h
@@ -1,8 +1,27 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
 
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <selinux/android.h>
 
 uint8_t kBase64Map[256] = {
@@ -74,7 +93,7 @@
 }
 
 bool WriteBase64ToFile(const char* base64, const std::string& file,
-        uid_t uid, gid_t gid, int mode) {
+        uid_t uid, gid_t gid, int mode, std::string* error_msg) {
     CHECK(base64 != nullptr);
     size_t length;
     std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
@@ -83,8 +102,10 @@
 
     int fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
 
+    using android::base::StringPrintf;
+
     if (fd < 0) {
-        PLOG(ERROR) << "Could not open file " << file;
+        *error_msg = StringPrintf("Could not open file %s: %s", file.c_str(), strerror(errno));
         return false;
     }
 
@@ -92,18 +113,18 @@
     while (wrote < length) {
         ssize_t cur = write(fd, bytes.get() + wrote, length - wrote);
         if (cur == -1) {
-            PLOG(ERROR) << "Could not write file " << file;
+            *error_msg = StringPrintf("Could not write file %s: %s", file.c_str(), strerror(errno));
             return false;
         }
         wrote += cur;
     }
 
     if (::chown(file.c_str(), uid, gid) != 0) {
-        PLOG(ERROR) << "Could not chown file " << file;
+        *error_msg = StringPrintf("Could not chown file %s: %s", file.c_str(), strerror(errno));
         return false;
     }
     if (::chmod(file.c_str(), mode) != 0) {
-        PLOG(ERROR) << "Could not chmod file " << file;
+        *error_msg = StringPrintf("Could not chmod file %s: %s", file.c_str(), strerror(errno));
         return false;
     }
     return true;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 1ff45e4..4eb1df0 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <fts.h>
 #include <stdlib.h>
+#include <sys/capability.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
@@ -34,6 +35,7 @@
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
+#include "dexopt_return_codes.h"
 #include "globals.h"  // extern variables.
 
 #ifndef LOG_TAG
@@ -43,6 +45,7 @@
 #define DEBUG_XATTRS 0
 
 using android::base::EndsWith;
+using android::base::Fdopendir;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
@@ -67,6 +70,35 @@
     CHECK(is_valid_package_name(package_name));
 }
 
+static std::string resolve_ce_path_by_inode_or_fallback(const std::string& root_path,
+        ino_t ce_data_inode, const std::string& fallback) {
+    if (ce_data_inode != 0) {
+        DIR* dir = opendir(root_path.c_str());
+        if (dir == nullptr) {
+            PLOG(ERROR) << "Failed to opendir " << root_path;
+            return fallback;
+        }
+
+        struct dirent* ent;
+        while ((ent = readdir(dir))) {
+            if (ent->d_ino == ce_data_inode) {
+                auto resolved = StringPrintf("%s/%s", root_path.c_str(), ent->d_name);
+                if (resolved != fallback) {
+                    LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
+                            << " instead of " << fallback;
+                }
+                closedir(dir);
+                return resolved;
+            }
+        }
+        LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
+        closedir(dir);
+        return fallback;
+    } else {
+        return fallback;
+    }
+}
+
 /**
  * Create the path name where package app contents should be stored for
  * the given volume UUID and package name.  An empty UUID is assumed to
@@ -110,34 +142,8 @@
     // For testing purposes, rely on the inode when defined; this could be
     // optimized to use access() in the future.
     auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
-    if (ce_data_inode != 0) {
-        auto user_path = create_data_user_ce_path(volume_uuid, user);
-        DIR* dir = opendir(user_path.c_str());
-        if (dir == nullptr) {
-            PLOG(ERROR) << "Failed to opendir " << user_path;
-            return fallback;
-        }
-
-        struct dirent* ent;
-        while ((ent = readdir(dir))) {
-            if (ent->d_ino == ce_data_inode) {
-                auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
-#if DEBUG_XATTRS
-                if (resolved != fallback) {
-                    LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
-                            << " instead of " << fallback;
-                }
-#endif
-                closedir(dir);
-                return resolved;
-            }
-        }
-        LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
-        closedir(dir);
-        return fallback;
-    } else {
-        return fallback;
-    }
+    auto user_path = create_data_user_ce_path(volume_uuid, user);
+    return resolve_ce_path_by_inode_or_fallback(user_path, ce_data_inode, fallback);
 }
 
 std::string create_data_user_de_package_path(const char* volume_uuid,
@@ -191,6 +197,46 @@
     return StringPrintf("%s/user_de/%u", data.c_str(), userid);
 }
 
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
+    return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
+}
+
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user) {
+    return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user);
+}
+
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id) {
+    return StringPrintf("%s/%d", create_data_misc_ce_rollback_base_path(volume_uuid, user).c_str(),
+          snapshot_id);
+}
+
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id) {
+    return StringPrintf("%s/%d", create_data_misc_de_rollback_base_path(volume_uuid, user).c_str(),
+          snapshot_id);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name) {
+    return StringPrintf("%s/%s",
+           create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode) {
+    auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshot_id,
+            package_name);
+    auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id);
+    return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
+}
+
+std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name) {
+    return StringPrintf("%s/%s",
+           create_data_misc_de_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
+}
+
 /**
  * Create the path name for media for a certain userid.
  */
@@ -198,10 +244,6 @@
     return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
 }
 
-std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name) {
-    return StringPrintf("%s/media/obb/%s", create_data_path(volume_uuid).c_str(), package_name);
-}
-
 std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
         const char* data_type, const char* package_name) {
     return StringPrintf("%s/Android/%s/%s", create_data_media_path(volume_uuid, userid).c_str(),
@@ -310,7 +352,7 @@
 
     std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
     DIR* dir = opendir(path.c_str());
-    if (dir == NULL) {
+    if (dir == nullptr) {
         // Unable to discover other users, but at least return owner
         PLOG(ERROR) << "Failed to opendir " << path;
         return users;
@@ -340,13 +382,13 @@
     FTSENT *p;
     int64_t matchedSize = 0;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         if (errno != ENOENT) {
             PLOG(ERROR) << "Failed to fts_open " << path;
         }
         return -1;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         switch (p->fts_info) {
         case FTS_D:
         case FTS_DEFAULT:
@@ -469,7 +511,7 @@
                 continue;
             }
             subdir = fdopendir(subfd);
-            if (subdir == NULL) {
+            if (subdir == nullptr) {
                 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
                 close(subfd);
                 result = -1;
@@ -494,12 +536,36 @@
     return result;
 }
 
+int create_dir_if_needed(const std::string& pathname, mode_t perms) {
+    struct stat st;
+
+    int rc;
+    if ((rc = stat(pathname.c_str(), &st)) != 0) {
+        if (errno == ENOENT) {
+            return mkdir(pathname.c_str(), perms);
+        } else {
+            return rc;
+        }
+    } else if (!S_ISDIR(st.st_mode)) {
+        LOG(DEBUG) << pathname << " is not a folder";
+        return -1;
+    }
+
+    mode_t actual_perms = st.st_mode & ALLPERMS;
+    if (actual_perms != perms) {
+        LOG(WARNING) << pathname << " permissions " << actual_perms << " expected " << perms;
+        return -1;
+    }
+
+    return 0;
+}
+
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
-    return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing);
+    return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
 }
 
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
-    return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing);
+    return delete_dir_contents(pathname.c_str(), 1, nullptr, ignore_if_missing);
 }
 
 int delete_dir_contents(const char *pathname,
@@ -511,7 +577,7 @@
     DIR *d;
 
     d = opendir(pathname);
-    if (d == NULL) {
+    if (d == nullptr) {
         if (ignore_if_missing && (errno == ENOENT)) {
             return 0;
         }
@@ -540,12 +606,12 @@
         return -1;
     }
     d = fdopendir(fd);
-    if (d == NULL) {
+    if (d == nullptr) {
         ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
         close(fd);
         return -1;
     }
-    res = _delete_dir_contents(d, 0);
+    res = _delete_dir_contents(d, nullptr);
     closedir(d);
     return res;
 }
@@ -573,7 +639,7 @@
     }
 
     DIR *ds = fdopendir(sdfd);
-    if (ds == NULL) {
+    if (ds == nullptr) {
         ALOGE("Couldn't fdopendir: %s\n", strerror(errno));
         return -1;
     }
@@ -619,18 +685,18 @@
                    uid_t group)
 {
     int res = 0;
-    DIR *ds = NULL;
-    DIR *dd = NULL;
+    DIR *ds = nullptr;
+    DIR *dd = nullptr;
 
     ds = opendir(srcname);
-    if (ds == NULL) {
+    if (ds == nullptr) {
         ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno));
         return -errno;
     }
 
     mkdir(dstname, 0600);
     dd = opendir(dstname);
-    if (dd == NULL) {
+    if (dd == nullptr) {
         ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno));
         closedir(ds);
         return -errno;
@@ -858,6 +924,8 @@
 static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
     if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
         return 0;
+    } else if (validate_path(android_staging_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) {
@@ -964,17 +1032,17 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(ERROR) << "Failed to fts_open " << path;
         return -1;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         switch (p->fts_info) {
         case FTS_DP:
             if (chmod(p->fts_path, target_mode) != 0) {
                 PLOG(WARNING) << "Failed to chmod " << p->fts_path;
             }
-            // Intentional fall through to also set GID
+            [[fallthrough]]; // to also set GID
         case FTS_F:
             if (chown(p->fts_path, -1, gid) != 0) {
                 PLOG(WARNING) << "Failed to chown " << p->fts_path;
@@ -1036,8 +1104,8 @@
                 continue;
             }
 
-            DIR* subdir = fdopendir(subdir_fd);
-            if (subdir == NULL) {
+            DIR* subdir = Fdopendir(std::move(subdir_fd));
+            if (subdir == nullptr) {
                 PLOG(WARNING) << "Could not open dir path " << local_path;
                 result = false;
                 continue;
@@ -1055,12 +1123,33 @@
 
 bool collect_profiles(std::vector<std::string>* profiles_paths) {
     DIR* d = opendir(android_profiles_dir.c_str());
-    if (d == NULL) {
+    if (d == nullptr) {
         return false;
     } else {
         return collect_profiles(d, android_profiles_dir, profiles_paths);
     }
 }
 
+void drop_capabilities(uid_t uid) {
+    if (setgid(uid) != 0) {
+        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetGid);
+    }
+    if (setuid(uid) != 0) {
+        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetUid);
+    }
+    // drop capabilities
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    if (capset(&capheader, &capdata[0]) < 0) {
+        PLOG(ERROR) << "capset failed";
+        exit(DexoptReturnCodes::kCapSet);
+    }
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5829c4f..6a42026 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,8 +36,6 @@
 #define BYPASS_QUOTA 0
 #define BYPASS_SDCARDFS 0
 
-#define APPLY_HARD_QUOTAS 0
-
 namespace android {
 namespace installd {
 
@@ -63,8 +61,20 @@
 std::string create_data_user_ce_package_path_as_user_link(
         const char* volume_uuid, userid_t userid, const char* package_name);
 
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id);
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+        int32_t snapshot_id);
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name);
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode);
+std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
+        userid_t user, int32_t snapshot_id, const char* package_name);
+
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
-std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
 std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
         const char* data_type, const char* package_name);
 
@@ -102,6 +112,8 @@
 bool is_valid_filename(const std::string& name);
 bool is_valid_package_name(const std::string& packageName);
 
+int create_dir_if_needed(const std::string& pathname, mode_t mode);
+
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
 
@@ -112,6 +124,8 @@
 
 int delete_dir_contents_fd(int dfd, const char *name);
 
+int rm_package_dir(const std::string& package_dir);
+
 int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t group);
 
 int64_t data_disk_free(const std::string& data_path);
@@ -142,6 +156,8 @@
 // It returns true if there were no errors at all, and false otherwise.
 bool collect_profiles(std::vector<std::string>* profiles_paths);
 
+void drop_capabilities(uid_t uid);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/utils_default.cpp b/cmds/installd/utils_default.cpp
new file mode 100644
index 0000000..a6025e6
--- /dev/null
+++ b/cmds/installd/utils_default.cpp
@@ -0,0 +1,30 @@
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "utils.h"
+
+namespace android {
+namespace installd {
+
+// In this file are default definitions of the functions that may contain
+// platform dependent logic.
+
+int rm_package_dir(const std::string& package_dir) {
+    return delete_dir_contents_and_dir(package_dir);
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
new file mode 100644
index 0000000..60d6492
--- /dev/null
+++ b/cmds/installd/view_compiler.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "view_compiler.h"
+
+#include <string>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "android-base/unique_fd.h"
+
+namespace android {
+namespace installd {
+
+using base::unique_fd;
+
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+                   int uid) {
+    CHECK(apk_path != nullptr);
+    CHECK(package_name != nullptr);
+    CHECK(out_dex_file != nullptr);
+
+    // viewcompiler won't have permission to open anything, so we have to open the files first
+    // and pass file descriptors.
+
+    // Open input file
+    unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open)
+    if (infd.get() < 0) {
+        PLOG(ERROR) << "Could not open input file: " << apk_path;
+        return false;
+    }
+
+    // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
+    // we close stdout and open it towards the right output.
+    unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)};
+    if (outfd.get() < 0) {
+        PLOG(ERROR) << "Could not open output file: " << out_dex_file;
+        return false;
+    }
+    if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
+        PLOG(ERROR) << "Could not change output file permissions";
+        return false;
+    }
+    if (dup2(outfd, STDOUT_FILENO) < 0) {
+        PLOG(ERROR) << "Could not duplicate output file descriptor";
+        return false;
+    }
+
+    // Prepare command line arguments for viewcompiler
+    std::string args[] = {"/system/bin/viewcompiler",
+                          "--apk",
+                          "--infd",
+                          android::base::StringPrintf("%d", infd.get()),
+                          "--dex",
+                          "--package",
+                          package_name};
+    char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
+                          const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
+                          const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
+                          const_cast<char*>(args[6].c_str()), nullptr};
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        // Now that we've opened the files we need, drop privileges.
+        drop_capabilities(uid);
+        execv("/system/bin/viewcompiler", argv);
+        _exit(1);
+    }
+
+    return wait_child(pid) == 0;
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/view_compiler.h b/cmds/installd/view_compiler.h
new file mode 100644
index 0000000..aa141ca
--- /dev/null
+++ b/cmds/installd/view_compiler.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIEW_COMPILER_H_
+#define VIEW_COMPILER_H_
+
+namespace android {
+namespace installd {
+
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+                   int uid);
+
+} // namespace installd
+} // namespace android
+
+#endif // VIEW_COMPILER_H_
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index 3b8955b..71f0837 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -95,6 +95,7 @@
         strncpy(ifr.ifr_name, interface, IFNAMSIZ);
         if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
             ALOGE("Cannot bring up %s: %s", interface, strerror(errno));
+            fclose(state);
             return 1;
         }
 
@@ -102,6 +103,7 @@
         if (!set_address(&ifr.ifr_addr, address) ||
                 ioctl(s, SIOCSIFADDR, &ifr)) {
             ALOGE("Cannot set address: %s", strerror(errno));
+            fclose(state);
             return 1;
         }
 
@@ -109,6 +111,7 @@
         if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) {
             if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
                 ALOGE("Cannot set netmask: %s", strerror(errno));
+                fclose(state);
                 return 1;
             }
         }
@@ -123,6 +126,7 @@
         fprintf(state, "%s\n", env("REMOTE_ADDR"));
     } else {
         ALOGE("Cannot parse parameters");
+        fclose(state);
         return 1;
     }
 
diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h
index 4f128ab..e19e3f7 100644
--- a/cmds/lshal/Command.h
+++ b/cmds/lshal/Command.h
@@ -27,7 +27,7 @@
 // Base class for all *Commands
 class Command {
 public:
-    Command(Lshal& lshal) : mLshal(lshal) {}
+    explicit Command(Lshal& lshal) : mLshal(lshal) {}
     virtual ~Command() = default;
     // Expect optind to be set by Lshal::main and points to the next argument
     // to process.
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index dd8812d..0952db6 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -59,8 +59,8 @@
 
     auto pair = splitFirst(mInterfaceName, '/');
 
-    FQName fqName(pair.first);
-    if (!fqName.isValid() || fqName.isIdentifier() || !fqName.isFullyQualified()) {
+    FQName fqName;
+    if (!FQName::parse(pair.first, &fqName) || fqName.isIdentifier() || !fqName.isFullyQualified()) {
         mLshal.err() << "Invalid fully-qualified name '" << pair.first << "'\n\n";
         return USAGE;
     }
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index 6e12008..3c3f56f 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -31,7 +31,7 @@
 
 class DebugCommand : public Command {
 public:
-    DebugCommand(Lshal &lshal) : Command(lshal) {}
+    explicit DebugCommand(Lshal &lshal) : Command(lshal) {}
     ~DebugCommand() = default;
     Status main(const Arg &arg) override;
     void usage() const override;
diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h
index cc709f8..da0cba6 100644
--- a/cmds/lshal/HelpCommand.h
+++ b/cmds/lshal/HelpCommand.h
@@ -31,7 +31,7 @@
 
 class HelpCommand : public Command {
 public:
-    HelpCommand(Lshal &lshal) : Command(lshal) {}
+    explicit HelpCommand(Lshal &lshal) : Command(lshal) {}
     ~HelpCommand() = default;
     Status main(const Arg &arg) override;
     void usage() const override;
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index ff22048..c706d91 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -18,14 +18,17 @@
 
 #include <getopt.h>
 
+#include <algorithm>
 #include <fstream>
+#include <functional>
 #include <iomanip>
 #include <iostream>
 #include <map>
-#include <sstream>
 #include <regex>
+#include <sstream>
 
 #include <android-base/file.h>
+#include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl-hash/Hash.h>
@@ -54,6 +57,19 @@
     return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
 }
 
+Partition toPartition(vintf::SchemaType t) {
+    switch (t) {
+        case vintf::SchemaType::FRAMEWORK: return Partition::SYSTEM;
+        // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM.
+        case vintf::SchemaType::DEVICE: return Partition::VENDOR;
+    }
+    return Partition::UNKNOWN;
+}
+
+std::string getPackageAndVersion(const std::string& fqInstance) {
+    return splitFirst(fqInstance, ':').first;
+}
+
 NullableOStream<std::ostream> ListCommand::out() const {
     return mLshal.out();
 }
@@ -74,6 +90,8 @@
 }
 
 const std::string &ListCommand::getCmdline(pid_t pid) {
+    static const std::string kEmptyString{};
+    if (pid == NO_PID) return kEmptyString;
     auto pair = mCmdlines.find(pid);
     if (pair != mCmdlines.end()) {
         return pair->second;
@@ -90,6 +108,7 @@
 }
 
 Partition ListCommand::getPartition(pid_t pid) {
+    if (pid == NO_PID) return Partition::UNKNOWN;
     auto it = mPartitions.find(pid);
     if (it != mPartitions.end()) {
         return it->second;
@@ -101,21 +120,19 @@
 
 // Give sensible defaults when nothing can be inferred from runtime.
 // process: Partition inferred from executable location or cmdline.
-Partition ListCommand::resolvePartition(Partition process, const FQName& fqName) const {
-    if (fqName.inPackage("vendor") ||
-        fqName.inPackage("com")) {
+Partition ListCommand::resolvePartition(Partition process, const FqInstance& fqInstance) const {
+    if (fqInstance.inPackage("vendor") || fqInstance.inPackage("com")) {
         return Partition::VENDOR;
     }
 
-    if (fqName.inPackage("android.frameworks") ||
-        fqName.inPackage("android.system") ||
-        fqName.inPackage("android.hidl")) {
+    if (fqInstance.inPackage("android.frameworks") || fqInstance.inPackage("android.system") ||
+        fqInstance.inPackage("android.hidl")) {
         return Partition::SYSTEM;
     }
 
     // Some android.hardware HALs are served from system. Check the value from executable
     // location / cmdline first.
-    if (fqName.inPackage("android.hardware")) {
+    if (fqInstance.inPackage("android.hardware")) {
         if (process != Partition::UNKNOWN) {
             return process;
         }
@@ -125,6 +142,67 @@
     return process;
 }
 
+bool match(const vintf::ManifestInstance& instance, const FqInstance& fqInstance,
+           vintf::TransportArch ta) {
+    // For hwbinder libs, allow missing arch in manifest.
+    // For passthrough libs, allow missing interface/instance in table.
+    return (ta.transport == instance.transport()) &&
+            (ta.transport == vintf::Transport::HWBINDER ||
+             vintf::contains(instance.arch(), ta.arch)) &&
+            (!fqInstance.hasInterface() || fqInstance.getInterface() == instance.interface()) &&
+            (!fqInstance.hasInstance() || fqInstance.getInstance() == instance.instance());
+}
+
+bool match(const vintf::MatrixInstance& instance, const FqInstance& fqInstance,
+           vintf::TransportArch /* ta */) {
+    return (!fqInstance.hasInterface() || fqInstance.getInterface() == instance.interface()) &&
+            (!fqInstance.hasInstance() || instance.matchInstance(fqInstance.getInstance()));
+}
+
+template <typename ObjectType>
+VintfInfo getVintfInfo(const std::shared_ptr<const ObjectType>& object,
+                       const FqInstance& fqInstance, vintf::TransportArch ta, VintfInfo value) {
+    bool found = false;
+    (void)object->forEachInstanceOfVersion(fqInstance.getPackage(), fqInstance.getVersion(),
+                                           [&](const auto& instance) {
+                                               found = match(instance, fqInstance, ta);
+                                               return !found; // continue if not found
+                                           });
+    return found ? value : VINTF_INFO_EMPTY;
+}
+
+std::shared_ptr<const vintf::HalManifest> ListCommand::getDeviceManifest() const {
+    return vintf::VintfObject::GetDeviceHalManifest();
+}
+
+std::shared_ptr<const vintf::CompatibilityMatrix> ListCommand::getDeviceMatrix() const {
+    return vintf::VintfObject::GetDeviceCompatibilityMatrix();
+}
+
+std::shared_ptr<const vintf::HalManifest> ListCommand::getFrameworkManifest() const {
+    return vintf::VintfObject::GetFrameworkHalManifest();
+}
+
+std::shared_ptr<const vintf::CompatibilityMatrix> ListCommand::getFrameworkMatrix() const {
+    return vintf::VintfObject::GetFrameworkCompatibilityMatrix();
+}
+
+VintfInfo ListCommand::getVintfInfo(const std::string& fqInstanceName,
+                                    vintf::TransportArch ta) const {
+    FqInstance fqInstance;
+    if (!fqInstance.setTo(fqInstanceName) &&
+        // Ignore interface / instance for passthrough libs
+        !fqInstance.setTo(getPackageAndVersion(fqInstanceName))) {
+        err() << "Warning: Cannot parse '" << fqInstanceName << "'; no VINTF info." << std::endl;
+        return VINTF_INFO_EMPTY;
+    }
+
+    return lshal::getVintfInfo(getDeviceManifest(), fqInstance, ta, DEVICE_MANIFEST) |
+            lshal::getVintfInfo(getFrameworkManifest(), fqInstance, ta, FRAMEWORK_MANIFEST) |
+            lshal::getVintfInfo(getDeviceMatrix(), fqInstance, ta, DEVICE_MATRIX) |
+            lshal::getVintfInfo(getFrameworkMatrix(), fqInstance, ta, FRAMEWORK_MATRIX);
+}
+
 static bool scanBinderContext(pid_t pid,
         const std::string &contextName,
         std::function<void(const std::string&)> eachLine) {
@@ -221,16 +299,40 @@
     return &pair.first->second;
 }
 
-// Must process hwbinder services first, then passthrough services.
+bool ListCommand::shouldFetchHalType(const HalType &type) const {
+    return (std::find(mFetchTypes.begin(), mFetchTypes.end(), type) != mFetchTypes.end());
+}
+
+Table* ListCommand::tableForType(HalType type) {
+    switch (type) {
+        case HalType::BINDERIZED_SERVICES:
+            return &mServicesTable;
+        case HalType::PASSTHROUGH_CLIENTS:
+            return &mPassthroughRefTable;
+        case HalType::PASSTHROUGH_LIBRARIES:
+            return &mImplementationsTable;
+        case HalType::VINTF_MANIFEST:
+            return &mManifestHalsTable;
+        case HalType::LAZY_HALS:
+            return &mLazyHalsTable;
+        default:
+            LOG(FATAL) << "Unknown HAL type " << static_cast<int64_t>(type);
+            return nullptr;
+    }
+}
+const Table* ListCommand::tableForType(HalType type) const {
+    return const_cast<ListCommand*>(this)->tableForType(type);
+}
+
 void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
-    f(mServicesTable);
-    f(mPassthroughRefTable);
-    f(mImplementationsTable);
+    for (const auto& type : mListTypes) {
+        f(*tableForType(type));
+    }
 }
 void ListCommand::forEachTable(const std::function<void(const Table &)> &f) const {
-    f(mServicesTable);
-    f(mPassthroughRefTable);
-    f(mImplementationsTable);
+    for (const auto& type : mListTypes) {
+        f(*tableForType(type));
+    }
 }
 
 void ListCommand::postprocess() {
@@ -246,22 +348,25 @@
             }
         }
         for (TableEntry& entry : table) {
-            entry.partition = getPartition(entry.serverPid);
+            if (entry.partition == Partition::UNKNOWN) {
+                entry.partition = getPartition(entry.serverPid);
+            }
+            entry.vintfInfo = getVintfInfo(entry.interfaceName, {entry.transport, entry.arch});
         }
     });
     // use a double for loop here because lshal doesn't care about efficiency.
     for (TableEntry &packageEntry : mImplementationsTable) {
         std::string packageName = packageEntry.interfaceName;
-        FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
-        if (!fqPackageName.isValid()) {
+        FQName fqPackageName;
+        if (!FQName::parse(packageName.substr(0, packageName.find("::")), &fqPackageName)) {
             continue;
         }
         for (TableEntry &interfaceEntry : mPassthroughRefTable) {
-            if (interfaceEntry.arch != ARCH_UNKNOWN) {
+            if (interfaceEntry.arch != vintf::Arch::ARCH_EMPTY) {
                 continue;
             }
-            FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
-            if (!interfaceName.isValid()) {
+            FQName interfaceName;
+            if (!FQName::parse(splitFirst(interfaceEntry.interfaceName, '/').first, &interfaceName)) {
                 continue;
             }
             if (interfaceName.getPackageAndVersion() == fqPackageName) {
@@ -271,169 +376,167 @@
     }
 
     mServicesTable.setDescription(
-            "All binderized services (registered services through hwservicemanager)");
+            "| All binderized services (registered with hwservicemanager)");
     mPassthroughRefTable.setDescription(
-            "All interfaces that getService() has ever return as a passthrough interface;\n"
-            "PIDs / processes shown below might be inaccurate because the process\n"
-            "might have relinquished the interface or might have died.\n"
-            "The Server / Server CMD column can be ignored.\n"
-            "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
-            "the library and successfully fetched the passthrough implementation.");
+            "| All interfaces that getService() has ever returned as a passthrough interface;\n"
+            "| PIDs / processes shown below might be inaccurate because the process\n"
+            "| might have relinquished the interface or might have died.\n"
+            "| The Server / Server CMD column can be ignored.\n"
+            "| The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+            "| the library and successfully fetched the passthrough implementation.");
     mImplementationsTable.setDescription(
-            "All available passthrough implementations (all -impl.so files).\n"
-            "These may return subclasses through their respective HIDL_FETCH_I* functions.");
+            "| All available passthrough implementations (all -impl.so files).\n"
+            "| These may return subclasses through their respective HIDL_FETCH_I* functions.");
+    mManifestHalsTable.setDescription(
+            "| All HALs that are in VINTF manifest.");
+    mLazyHalsTable.setDescription(
+            "| All HALs that are declared in VINTF manifest:\n"
+            "|    - as hwbinder HALs but are not registered to hwservicemanager, and\n"
+            "|    - as hwbinder/passthrough HALs with no implementation.");
 }
 
-static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
-    for (vintf::Version& v : hal->versions) {
-        if (v.majorVer == version.majorVer) {
-            v.minorVer = std::max(v.minorVer, version.minorVer);
-            return true;
-        }
+bool ListCommand::addEntryWithInstance(const TableEntry& entry,
+                                       vintf::HalManifest* manifest) const {
+    FqInstance fqInstance;
+    if (!fqInstance.setTo(entry.interfaceName)) {
+        err() << "Warning: '" << entry.interfaceName << "' is not a valid FqInstance." << std::endl;
+        return false;
     }
-    return false;
+
+    if (fqInstance.getPackage() == gIBaseFqName.package()) {
+        return true; // always remove IBase from manifest
+    }
+
+    Partition partition = resolvePartition(entry.partition, fqInstance);
+
+    if (partition == Partition::UNKNOWN) {
+        err() << "Warning: Cannot guess the partition of FqInstance " << fqInstance.string()
+              << std::endl;
+        return false;
+    }
+
+    if (partition != mVintfPartition) {
+        return true; // strip out instances that is in a different partition.
+    }
+
+    vintf::Arch arch;
+    if (entry.transport == vintf::Transport::HWBINDER) {
+        arch = vintf::Arch::ARCH_EMPTY; // no need to specify arch in manifest
+    } else if (entry.transport == vintf::Transport::PASSTHROUGH) {
+        if (entry.arch == vintf::Arch::ARCH_EMPTY) {
+            err() << "Warning: '" << entry.interfaceName << "' doesn't have bitness info.";
+            return false;
+        }
+        arch = entry.arch;
+    } else {
+        err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+        return false;
+    }
+
+    std::string e;
+    if (!manifest->insertInstance(fqInstance, entry.transport, arch, vintf::HalFormat::HIDL, &e)) {
+        err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool ListCommand::addEntryWithoutInstance(const TableEntry& entry,
+                                          const vintf::HalManifest* manifest) const {
+    const auto& packageAndVersion = splitFirst(getPackageAndVersion(entry.interfaceName), '@');
+    const auto& package = packageAndVersion.first;
+    vintf::Version version;
+    if (!vintf::parse(packageAndVersion.second, &version)) {
+        err() << "Warning: Cannot parse version '" << packageAndVersion.second << "' for entry '"
+              << entry.interfaceName << "'" << std::endl;
+        return false;
+    }
+
+    bool found = false;
+    (void)manifest->forEachInstanceOfVersion(package, version, [&found](const auto&) {
+        found = true;
+        return false; // break
+    });
+    return found;
 }
 
 void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
     using vintf::operator|=;
     using vintf::operator<<;
+    using namespace std::placeholders;
 
     vintf::HalManifest manifest;
     manifest.setType(toSchemaType(mVintfPartition));
-    forEachTable([this, &manifest] (const Table &table) {
-        for (const TableEntry &entry : table) {
 
-            std::string fqInstanceName = entry.interfaceName;
+    std::vector<std::string> error;
+    for (const TableEntry& entry : mServicesTable)
+        if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
+    for (const TableEntry& entry : mPassthroughRefTable)
+        if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
+    for (const TableEntry& entry : mManifestHalsTable)
+        if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
 
-            if (&table == &mImplementationsTable) {
-                // Quick hack to work around *'s
-                replaceAll(&fqInstanceName, '*', 'D');
-            }
-            auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
-            FQName fqName(splittedFqInstanceName.first);
-            if (!fqName.isValid()) {
-                err() << "Warning: '" << splittedFqInstanceName.first
-                     << "' is not a valid FQName." << std::endl;
-                continue;
-            }
+    std::vector<std::string> passthrough;
+    for (const TableEntry& entry : mImplementationsTable)
+        if (!addEntryWithoutInstance(entry, &manifest)) passthrough.push_back(entry.interfaceName);
 
-            if (fqName.package() == gIBaseFqName.package()) {
-                continue; // always remove IBase from manifest
-            }
-
-            Partition partition = resolvePartition(entry.partition, fqName);
-
-            if (partition == Partition::UNKNOWN) {
-                err() << "Warning: Cannot guess the partition of instance " << fqInstanceName
-                      << ". It is removed from the generated manifest." << std::endl;
-                continue;
-            }
-
-            if (partition != mVintfPartition) {
-                continue; // strip out instances that is in a different partition.
-            }
-
-            std::string interfaceName =
-                    &table == &mImplementationsTable ? "" : fqName.name();
-            std::string instanceName =
-                    &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
-
-            vintf::Version version{fqName.getPackageMajorVersion(),
-                                   fqName.getPackageMinorVersion()};
-            vintf::Transport transport;
-            vintf::Arch arch;
-            if (entry.transport == "hwbinder") {
-                transport = vintf::Transport::HWBINDER;
-                arch = vintf::Arch::ARCH_EMPTY;
-            } else if (entry.transport == "passthrough") {
-                transport = vintf::Transport::PASSTHROUGH;
-                switch (entry.arch) {
-                    case lshal::ARCH32:
-                        arch = vintf::Arch::ARCH_32;    break;
-                    case lshal::ARCH64:
-                        arch = vintf::Arch::ARCH_64;    break;
-                    case lshal::ARCH_BOTH:
-                        arch = vintf::Arch::ARCH_32_64; break;
-                    case lshal::ARCH_UNKNOWN: // fallthrough
-                    default:
-                        err() << "Warning: '" << fqName.package()
-                             << "' doesn't have bitness info, assuming 32+64." << std::endl;
-                        arch = vintf::Arch::ARCH_32_64;
-                }
-            } else {
-                err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
-                continue;
-            }
-
-            bool done = false;
-            for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
-                if (hal->transport() != transport) {
-                    if (transport != vintf::Transport::PASSTHROUGH) {
-                        err() << "Fatal: should not reach here. Generated result may be wrong for '"
-                             << hal->name << "'."
-                             << std::endl;
-                    }
-                    done = true;
-                    break;
-                }
-                if (findAndBumpVersion(hal, version)) {
-                    if (&table != &mImplementationsTable) {
-                        hal->insertLegacyInstance(interfaceName, instanceName);
-                    }
-                    hal->transportArch.arch |= arch;
-                    done = true;
-                    break;
-                }
-            }
-            if (done) {
-                continue; // to next TableEntry
-            }
-            vintf::ManifestHal manifestHal{
-                    vintf::HalFormat::HIDL,
-                    std::string{fqName.package()},
-                    {version},
-                    {transport, arch},
-                    {}};
-            if (&table != &mImplementationsTable) {
-                manifestHal.insertLegacyInstance(interfaceName, instanceName);
-            }
-            if (!manifest.add(std::move(manifestHal))) {
-                err() << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
-            }
-        }
-    });
     out << "<!-- " << std::endl
-         << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
-         << INIT_VINTF_NOTES
-         << "-->" << std::endl;
-    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_NO_FQNAME);
+        << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
+        << INIT_VINTF_NOTES;
+    if (!error.empty()) {
+        out << std::endl << "    The following HALs are not added; see warnings." << std::endl;
+        for (const auto& e : error) {
+            out << "        " << e << std::endl;
+        }
+    }
+    if (!passthrough.empty()) {
+        out << std::endl
+            << "    The following HALs are passthrough and no interface or instance " << std::endl
+            << "    names can be inferred." << std::endl;
+        for (const auto& e : passthrough) {
+            out << "        " << e << std::endl;
+        }
+    }
+    out << "-->" << std::endl;
+    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlags::HALS_ONLY);
 }
 
 std::string ListCommand::INIT_VINTF_NOTES{
-    "    1. If a HAL is supported in both hwbinder and passthrough transport, \n"
+    "    1. If a HAL is supported in both hwbinder and passthrough transport,\n"
     "       only hwbinder is shown.\n"
     "    2. It is likely that HALs in passthrough transport does not have\n"
     "       <interface> declared; users will have to write them by hand.\n"
     "    3. A HAL with lower minor version can be overridden by a HAL with\n"
     "       higher minor version if they have the same name and major version.\n"
+    "    4. This output is intended for launch devices.\n"
+    "       Upgrading devices should not use this tool to generate device\n"
+    "       manifest and replace the existing manifest directly, but should\n"
+    "       edit the existing manifest manually.\n"
+    "       Specifically, devices which launched at Android O-MR1 or earlier\n"
+    "       should not use the 'fqname' format for required HAL entries and\n"
+    "       should instead use the legacy package, name, instance-name format\n"
+    "       until they are updated.\n"
 };
 
-static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+static vintf::Arch fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
     switch (a) {
         case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
-            return ARCH64;
+            return vintf::Arch::ARCH_64;
         case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
-            return ARCH32;
+            return vintf::Arch::ARCH_32;
         case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
         default:
-            return ARCH_UNKNOWN;
+            return vintf::Arch::ARCH_EMPTY;
     }
 }
 
 void ListCommand::dumpTable(const NullableOStream<std::ostream>& out) const {
     if (mNeat) {
-        MergedTable({&mServicesTable, &mPassthroughRefTable, &mImplementationsTable})
-            .createTextTable().dump(out.buf());
+        std::vector<const Table*> tables;
+        forEachTable([&tables](const Table &table) {
+            tables.push_back(&table);
+        });
+        MergedTable(std::move(tables)).createTextTable().dump(out.buf());
         return;
     }
 
@@ -481,24 +584,13 @@
     return OK;
 }
 
-void ListCommand::putEntry(TableEntrySource source, TableEntry &&entry) {
-    Table *table = nullptr;
-    switch (source) {
-        case HWSERVICEMANAGER_LIST :
-            table = &mServicesTable; break;
-        case PTSERVICEMANAGER_REG_CLIENT :
-            table = &mPassthroughRefTable; break;
-        case LIST_DLLIB :
-            table = &mImplementationsTable; break;
-        default:
-            err() << "Error: Unknown source of entry " << source << std::endl;
-    }
-    if (table) {
-        table->add(std::forward<TableEntry>(entry));
-    }
+void ListCommand::putEntry(HalType type, TableEntry &&entry) {
+    tableForType(type)->add(std::forward<TableEntry>(entry));
 }
 
 Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) {
+    if (!shouldFetchHalType(HalType::PASSTHROUGH_LIBRARIES)) { return OK; }
+
     using namespace ::android::hardware;
     using namespace ::android::hidl::manager::V1_0;
     using namespace ::android::hidl::base::V1_0;
@@ -510,12 +602,12 @@
                     std::string{info.instanceName.c_str()};
             entries.emplace(interfaceName, TableEntry{
                 .interfaceName = interfaceName,
-                .transport = "passthrough",
+                .transport = vintf::Transport::PASSTHROUGH,
                 .clientPids = info.clientPids,
             }).first->second.arch |= fromBaseArchitecture(info.arch);
         }
         for (auto &&pair : entries) {
-            putEntry(LIST_DLLIB, std::move(pair.second));
+            putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second));
         }
     });
     if (!ret.isOk()) {
@@ -527,6 +619,8 @@
 }
 
 Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) {
+    if (!shouldFetchHalType(HalType::PASSTHROUGH_CLIENTS)) { return OK; }
+
     using namespace ::android::hardware;
     using namespace ::android::hardware::details;
     using namespace ::android::hidl::manager::V1_0;
@@ -536,11 +630,11 @@
             if (info.clientPids.size() <= 0) {
                 continue;
             }
-            putEntry(PTSERVICEMANAGER_REG_CLIENT, {
+            putEntry(HalType::PASSTHROUGH_CLIENTS, {
                 .interfaceName =
                         std::string{info.interfaceName.c_str()} + "/" +
                         std::string{info.instanceName.c_str()},
-                .transport = "passthrough",
+                .transport = vintf::Transport::PASSTHROUGH,
                 .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
                 .clientPids = info.clientPids,
                 .arch = fromBaseArchitecture(info.arch)
@@ -556,8 +650,11 @@
 }
 
 Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
-    const std::string mode = "hwbinder";
+    using vintf::operator<<;
 
+    if (!shouldFetchHalType(HalType::BINDERIZED_SERVICES)) { return OK; }
+
+    const vintf::Transport mode = vintf::Transport::HWBINDER;
     hidl_vec<hidl_string> fqInstanceNames;
     // copying out for timeoutIPC
     auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
@@ -576,12 +673,13 @@
         TableEntry& entry = allTableEntries[fqInstanceName];
         entry.interfaceName = fqInstanceName;
         entry.transport = mode;
+        entry.serviceStatus = ServiceStatus::NON_RESPONSIVE;
 
         status |= fetchBinderizedEntry(manager, &entry);
     }
 
     for (auto& pair : allTableEntries) {
-        putEntry(HWSERVICEMANAGER_LIST, std::move(pair.second));
+        putEntry(HalType::BINDERIZED_SERVICES, std::move(pair.second));
     }
     return status;
 }
@@ -681,9 +779,100 @@
             handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
         }
     } while (0);
+    if (status == OK) {
+        entry->serviceStatus = ServiceStatus::ALIVE;
+    }
     return status;
 }
 
+Status ListCommand::fetchManifestHals() {
+    if (!shouldFetchHalType(HalType::VINTF_MANIFEST)) { return OK; }
+    Status status = OK;
+
+    for (auto manifest : {getDeviceManifest(), getFrameworkManifest()}) {
+        if (manifest == nullptr) {
+            status |= VINTF_ERROR;
+            continue;
+        }
+
+        std::map<std::string, TableEntry> entries;
+
+        manifest->forEachInstance([&] (const vintf::ManifestInstance& manifestInstance) {
+            TableEntry entry{
+                .interfaceName = manifestInstance.getFqInstance().string(),
+                .transport = manifestInstance.transport(),
+                .arch = manifestInstance.arch(),
+                // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM.
+                .partition = toPartition(manifest->type()),
+                .serviceStatus = ServiceStatus::DECLARED};
+            std::string key = entry.interfaceName;
+            entries.emplace(std::move(key), std::move(entry));
+            return true;
+        });
+
+        for (auto&& pair : entries)
+            mManifestHalsTable.add(std::move(pair.second));
+    }
+    return status;
+}
+
+Status ListCommand::fetchLazyHals() {
+    using vintf::operator<<;
+
+    if (!shouldFetchHalType(HalType::LAZY_HALS)) { return OK; }
+    Status status = OK;
+
+    for (const TableEntry& manifestEntry : mManifestHalsTable) {
+        if (manifestEntry.transport == vintf::Transport::HWBINDER) {
+            if (!hasHwbinderEntry(manifestEntry)) {
+                mLazyHalsTable.add(TableEntry(manifestEntry));
+            }
+            continue;
+        }
+        if (manifestEntry.transport == vintf::Transport::PASSTHROUGH) {
+            if (!hasPassthroughEntry(manifestEntry)) {
+                mLazyHalsTable.add(TableEntry(manifestEntry));
+            }
+            continue;
+        }
+        err() << "Warning: unrecognized transport in VINTF manifest: "
+              << manifestEntry.transport;
+        status |= VINTF_ERROR;
+    }
+    return status;
+}
+
+bool ListCommand::hasHwbinderEntry(const TableEntry& entry) const {
+    for (const TableEntry& existing : mServicesTable) {
+        if (existing.interfaceName == entry.interfaceName) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool ListCommand::hasPassthroughEntry(const TableEntry& entry) const {
+    FqInstance entryFqInstance;
+    if (!entryFqInstance.setTo(entry.interfaceName)) {
+        return false; // cannot parse, so add it anyway.
+    }
+    for (const TableEntry& existing : mImplementationsTable) {
+        FqInstance existingFqInstance;
+        if (!existingFqInstance.setTo(getPackageAndVersion(existing.interfaceName))) {
+            continue;
+        }
+
+        // For example, manifest may say graphics.mapper@2.1 but passthroughServiceManager
+        // can only list graphics.mapper@2.0.
+        if (entryFqInstance.getPackage() == existingFqInstance.getPackage() &&
+            vintf::Version{entryFqInstance.getVersion()}
+                .minorAtLeast(vintf::Version{existingFqInstance.getVersion()})) {
+            return true;
+        }
+    }
+    return false;
+}
+
 Status ListCommand::fetch() {
     Status status = OK;
     auto bManager = mLshal.serviceManager();
@@ -703,9 +892,27 @@
     } else {
         status |= fetchAllLibraries(pManager);
     }
+    status |= fetchManifestHals();
+    status |= fetchLazyHals();
     return status;
 }
 
+void ListCommand::initFetchTypes() {
+    // TODO: refactor to do polymorphism on each table (so that dependency graph is not hardcoded).
+    static const std::map<HalType, std::set<HalType>> kDependencyGraph{
+        {HalType::LAZY_HALS, {HalType::BINDERIZED_SERVICES,
+                              HalType::PASSTHROUGH_LIBRARIES,
+                              HalType::VINTF_MANIFEST}},
+    };
+    mFetchTypes.insert(mListTypes.begin(), mListTypes.end());
+    for (HalType listType : mListTypes) {
+        auto it = kDependencyGraph.find(listType);
+        if (it != kDependencyGraph.end()) {
+            mFetchTypes.insert(it->second.begin(), it->second.end());
+        }
+    }
+}
+
 void ListCommand::registerAllOptions() {
     int v = mOptions.size();
     // A list of acceptable command line options
@@ -721,7 +928,7 @@
     mOptions.push_back({'l', "released", no_argument, v++, [](ListCommand* thiz, const char*) {
         thiz->mSelectedColumns.push_back(TableColumnType::RELEASED);
         return OK;
-    }, "print the 'is released?' column\n(Y=released, empty=unreleased or unknown)"});
+    }, "print the 'is released?' column\n(Y=released, N=unreleased, ?=unknown)"});
     mOptions.push_back({'t', "transport", no_argument, v++, [](ListCommand* thiz, const char*) {
         thiz->mSelectedColumns.push_back(TableColumnType::TRANSPORT);
         return OK;
@@ -761,6 +968,23 @@
     }, "Emit debug info from\nIBase::debug with empty options. Cannot be used with --neat.\n"
         "Writes to specified file if 'arg' is provided, otherwise stdout."});
 
+    mOptions.push_back({'V', "vintf", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::VINTF);
+        return OK;
+    }, "print VINTF info. This column contains a comma-separated list of:\n"
+       "    - DM: if the HAL is in the device manifest\n"
+       "    - DC: if the HAL is in the device compatibility matrix\n"
+       "    - FM: if the HAL is in the framework manifest\n"
+       "    - FC: if the HAL is in the framework compatibility matrix"});
+    mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
+        return OK;
+    }, "print service status column. Possible values are:\n"
+       "    - alive: alive and running hwbinder service;\n"
+       "    - registered;dead: registered to hwservicemanager but is not responsive;\n"
+       "    - declared: only declared in VINTF manifest but is not registered to hwservicemanager;\n"
+       "    - N/A: no information for passthrough HALs."});
+
     // long options without short alternatives
     mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
         thiz->mVintf = true;
@@ -791,6 +1015,46 @@
         thiz->mNeat = true;
         return OK;
     }, "output is machine parsable (no explanatory text).\nCannot be used with --debug."});
+    mOptions.push_back({'\0', "types", required_argument, v++, [](ListCommand* thiz, const char* arg) {
+        if (!arg) { return USAGE; }
+
+        static const std::map<std::string, HalType> kHalTypeMap {
+            {"binderized", HalType::BINDERIZED_SERVICES},
+            {"b", HalType::BINDERIZED_SERVICES},
+            {"passthrough_clients", HalType::PASSTHROUGH_CLIENTS},
+            {"c", HalType::PASSTHROUGH_CLIENTS},
+            {"passthrough_libs", HalType::PASSTHROUGH_LIBRARIES},
+            {"l", HalType::PASSTHROUGH_LIBRARIES},
+            {"vintf", HalType::VINTF_MANIFEST},
+            {"v", HalType::VINTF_MANIFEST},
+            {"lazy", HalType::LAZY_HALS},
+            {"z", HalType::LAZY_HALS},
+        };
+
+        std::vector<std::string> halTypesArgs = split(std::string(arg), ',');
+        for (const auto& halTypeArg : halTypesArgs) {
+            if (halTypeArg.empty()) continue;
+
+            const auto& halTypeIter = kHalTypeMap.find(halTypeArg);
+            if (halTypeIter == kHalTypeMap.end()) {
+
+                thiz->err() << "Unrecognized HAL type: " << halTypeArg << std::endl;
+                return USAGE;
+            }
+
+            // Append unique (non-repeated) HAL types to the reporting list
+            HalType halType = halTypeIter->second;
+            if (std::find(thiz->mListTypes.begin(), thiz->mListTypes.end(), halType) ==
+                thiz->mListTypes.end()) {
+                thiz->mListTypes.push_back(halType);
+            }
+        }
+
+        if (thiz->mListTypes.empty()) { return USAGE; }
+        return OK;
+    }, "comma-separated list of one or more sections.\nThe output is restricted to the selected "
+       "section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
+       "passthrough_libs), (v|vintf), and (z|lazy).\nDefault is `bcl`."});
 }
 
 // Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
@@ -809,9 +1073,9 @@
         i++;
     }
     // getopt_long last option has all zeros
-    ret[i].name = NULL;
+    ret[i].name = nullptr;
     ret[i].has_arg = 0;
-    ret[i].flag = NULL;
+    ret[i].flag = nullptr;
     ret[i].val = 0;
 
     return ret;
@@ -829,6 +1093,7 @@
 }
 
 Status ListCommand::parseArgs(const Arg &arg) {
+    mListTypes.clear();
 
     if (mOptions.empty()) {
         registerAllOptions();
@@ -885,7 +1150,7 @@
     }
 
     if (mSelectedColumns.empty()) {
-        mSelectedColumns = {TableColumnType::RELEASED,
+        mSelectedColumns = {TableColumnType::VINTF, TableColumnType::RELEASED,
                             TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
                             TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
     }
@@ -901,6 +1166,13 @@
         }
     }
 
+    // By default, list all HAL types
+    if (mListTypes.empty()) {
+        mListTypes = {HalType::BINDERIZED_SERVICES, HalType::PASSTHROUGH_CLIENTS,
+                      HalType::PASSTHROUGH_LIBRARIES};
+    }
+    initFetchTypes();
+
     forEachTable([this] (Table& table) {
         table.setSelectedColumns(this->mSelectedColumns);
     });
@@ -919,22 +1191,6 @@
     return status;
 }
 
-static std::vector<std::string> splitString(const std::string &s, char c) {
-    std::vector<std::string> components;
-
-    size_t startPos = 0;
-    size_t matchPos;
-    while ((matchPos = s.find(c, startPos)) != std::string::npos) {
-        components.push_back(s.substr(startPos, matchPos - startPos));
-        startPos = matchPos + 1;
-    }
-
-    if (startPos <= s.length()) {
-        components.push_back(s.substr(startPos));
-    }
-    return components;
-}
-
 const std::string& ListCommand::RegisteredOption::getHelpMessageForArgument() const {
     static const std::string empty{};
     static const std::string optional{"[=<arg>]"};
@@ -954,7 +1210,7 @@
     err() << "list:" << std::endl
           << "    lshal" << std::endl
           << "    lshal list" << std::endl
-          << "        List all hals with default ordering and columns (`lshal list -riepc`)" << std::endl
+          << "        List all hals with default ordering and columns (`lshal list -Vliepc`)" << std::endl
           << "    lshal list [-h|--help]" << std::endl
           << "        -h, --help: Print help message for list (`lshal help list`)" << std::endl
           << "    lshal [list] [OPTIONS...]" << std::endl;
@@ -970,7 +1226,7 @@
         if (!e.longOption.empty())
             err() << "--" << e.longOption << e.getHelpMessageForArgument();
         err() << ": ";
-        std::vector<std::string> lines = splitString(e.help, '\n');
+        std::vector<std::string> lines = split(e.help, '\n');
         for (const auto& line : lines) {
             if (&line != &lines.front())
                 err() << "            ";
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 1e85ea0..85195fc 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -26,7 +26,9 @@
 
 #include <android-base/macros.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
-#include <hidl-util/FQName.h>
+#include <hidl-util/FqInstance.h>
+#include <vintf/HalManifest.h>
+#include <vintf/VintfObject.h>
 
 #include "Command.h"
 #include "NullableOStream.h"
@@ -45,9 +47,17 @@
     uint32_t threadCount; // number of threads total
 };
 
+enum class HalType {
+    BINDERIZED_SERVICES = 0,
+    PASSTHROUGH_CLIENTS,
+    PASSTHROUGH_LIBRARIES,
+    VINTF_MANIFEST,
+    LAZY_HALS,
+};
+
 class ListCommand : public Command {
 public:
-    ListCommand(Lshal &lshal) : Command(lshal) {}
+    explicit ListCommand(Lshal &lshal) : Command(lshal) {}
     virtual ~ListCommand() = default;
     Status main(const Arg &arg) override;
     void usage() const override;
@@ -80,13 +90,17 @@
 
 protected:
     Status parseArgs(const Arg &arg);
+    // Retrieve first-hand information
     Status fetch();
+    // Retrieve derived information base on existing table
     virtual void postprocess();
     Status dump();
-    void putEntry(TableEntrySource source, TableEntry &&entry);
+    void putEntry(HalType type, TableEntry &&entry);
     Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+    Status fetchManifestHals();
+    Status fetchLazyHals();
 
     Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
                                 TableEntry *entry);
@@ -113,19 +127,43 @@
     void removeDeadProcesses(Pids *pids);
 
     virtual Partition getPartition(pid_t pid);
-    Partition resolvePartition(Partition processPartition, const FQName& fqName) const;
+    Partition resolvePartition(Partition processPartition, const FqInstance &fqInstance) const;
+
+    VintfInfo getVintfInfo(const std::string &fqInstanceName, vintf::TransportArch ta) const;
+    // Allow to mock these functions for testing.
+    virtual std::shared_ptr<const vintf::HalManifest> getDeviceManifest() const;
+    virtual std::shared_ptr<const vintf::CompatibilityMatrix> getDeviceMatrix() const;
+    virtual std::shared_ptr<const vintf::HalManifest> getFrameworkManifest() const;
+    virtual std::shared_ptr<const vintf::CompatibilityMatrix> getFrameworkMatrix() const;
 
     void forEachTable(const std::function<void(Table &)> &f);
     void forEachTable(const std::function<void(const Table &)> &f) const;
+    Table* tableForType(HalType type);
+    const Table* tableForType(HalType type) const;
 
     NullableOStream<std::ostream> err() const;
     NullableOStream<std::ostream> out() const;
 
     void registerAllOptions();
 
+    // helper functions to dumpVintf.
+    bool addEntryWithInstance(const TableEntry &entry, vintf::HalManifest *manifest) const;
+    bool addEntryWithoutInstance(const TableEntry &entry, const vintf::HalManifest *manifest) const;
+
+    // Helper function. Whether to fetch entries corresponding to a given HAL type.
+    bool shouldFetchHalType(const HalType &type) const;
+
+    void initFetchTypes();
+
+    // Helper functions ti add HALs that are listed in VINTF manifest to LAZY_HALS table.
+    bool hasHwbinderEntry(const TableEntry& entry) const;
+    bool hasPassthroughEntry(const TableEntry& entry) const;
+
     Table mServicesTable{};
     Table mPassthroughRefTable{};
     Table mImplementationsTable{};
+    Table mManifestHalsTable{};
+    Table mLazyHalsTable{};
 
     std::string mFileOutputPath;
     TableEntryCompare mSortColumn = nullptr;
@@ -139,6 +177,11 @@
     // If true, explanatory text are not emitted.
     bool mNeat = false;
 
+    // Type(s) of HAL associations to list.
+    std::vector<HalType> mListTypes{};
+    // Type(s) of HAL associations to fetch.
+    std::set<HalType> mFetchTypes{};
+
     // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
     // If an entry exist but is an empty string, process might have died.
     // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h
index ab37a04..737d3a2 100644
--- a/cmds/lshal/NullableOStream.h
+++ b/cmds/lshal/NullableOStream.h
@@ -25,8 +25,8 @@
 template<typename S>
 class NullableOStream {
 public:
-    NullableOStream(S &os) : mOs(&os) {}
-    NullableOStream(S *os) : mOs(os) {}
+    explicit NullableOStream(S &os) : mOs(&os) {}
+    explicit NullableOStream(S *os) : mOs(os) {}
     NullableOStream &operator=(S &os) {
         mOs = &os;
         return *this;
@@ -57,7 +57,7 @@
     S& buf() const {
         return *mOs;
     }
-    operator bool() const {
+    operator bool() const { // NOLINT(google-explicit-constructor)
         return mOs != nullptr;
     }
 private:
diff --git a/cmds/lshal/OWNERS b/cmds/lshal/OWNERS
new file mode 100644
index 0000000..60038da
--- /dev/null
+++ b/cmds/lshal/OWNERS
@@ -0,0 +1,2 @@
+elsk@google.com
+smoreland@google.com
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index fc40749..820679f 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -16,34 +16,75 @@
 
 #include "PipeRelay.h"
 
-#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <atomic>
+
+#include <android-base/logging.h>
 #include <utils/Thread.h>
 
 namespace android {
 namespace lshal {
 
+static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
+
 struct PipeRelay::RelayThread : public Thread {
     explicit RelayThread(int fd, std::ostream &os);
 
     bool threadLoop() override;
+    void setFinished();
 
 private:
     int mFd;
     std::ostream &mOutStream;
 
+    // If we were to use requestExit() and exitPending() instead, threadLoop()
+    // may not run at all by the time ~PipeRelay is called (i.e. debug() has
+    // returned from HAL). By using our own flag, we ensure that select() and
+    // read() are executed until data are drained.
+    std::atomic_bool mFinished;
+
     DISALLOW_COPY_AND_ASSIGN(RelayThread);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
-    : mFd(fd),
-      mOutStream(os) {
-}
+      : mFd(fd), mOutStream(os), mFinished(false) {}
 
 bool PipeRelay::RelayThread::threadLoop() {
     char buffer[1024];
-    ssize_t n = read(mFd, buffer, sizeof(buffer));
+
+    fd_set set;
+    FD_ZERO(&set);
+    FD_SET(mFd, &set);
+
+    struct timeval timeout = READ_TIMEOUT;
+
+    int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
+    if (res < 0) {
+        PLOG(INFO) << "select() failed";
+        return false;
+    }
+
+    if (res == 0 || !FD_ISSET(mFd, &set)) {
+        if (mFinished) {
+            LOG(WARNING) << "debug: timeout reading from pipe, output may be truncated.";
+            return false;
+        }
+        // timeout, but debug() has not returned, so wait for HAL to finish.
+        return true;
+    }
+
+    // FD_ISSET(mFd, &set) == true. Data available, start reading
+    ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
+
+    if (n < 0) {
+        PLOG(ERROR) << "read() failed";
+    }
 
     if (n <= 0) {
         return false;
@@ -54,11 +95,15 @@
     return true;
 }
 
+void PipeRelay::RelayThread::setFinished() {
+    mFinished = true;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 PipeRelay::PipeRelay(std::ostream &os)
     : mInitCheck(NO_INIT) {
-    int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
+    int res = pipe(mFds);
 
     if (res < 0) {
         mInitCheck = -errno;
@@ -77,20 +122,14 @@
 }
 
 PipeRelay::~PipeRelay() {
-    if (mFds[1] >= 0) {
-        shutdown(mFds[1], SHUT_WR);
-    }
+    CloseFd(&mFds[1]);
 
-    if (mFds[0] >= 0) {
-        shutdown(mFds[0], SHUT_RD);
-    }
-
-    if (mThread != NULL) {
+    if (mThread != nullptr) {
+        mThread->setFinished();
         mThread->join();
         mThread.clear();
     }
 
-    CloseFd(&mFds[1]);
     CloseFd(&mFds[0]);
 }
 
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index e8792a4..8e21975 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -16,7 +16,11 @@
 #define LOG_TAG "lshal"
 #include <android-base/logging.h>
 
+#include <map>
+
+#include <android-base/strings.h>
 #include <hidl-hash/Hash.h>
+#include <vintf/parse_string.h>
 
 #include "TableEntry.h"
 
@@ -26,19 +30,19 @@
 namespace android {
 namespace lshal {
 
-static const std::string &getArchString(Architecture arch) {
+static const std::string &getArchString(vintf::Arch arch) {
     static const std::string sStr64 = "64";
     static const std::string sStr32 = "32";
     static const std::string sStrBoth = "32+64";
-    static const std::string sStrUnknown = "";
+    static const std::string sStrUnknown = "?";
     switch (arch) {
-        case ARCH64:
+        case vintf::Arch::ARCH_64:
             return sStr64;
-        case ARCH32:
+        case vintf::Arch::ARCH_32:
             return sStr32;
-        case ARCH_BOTH:
+        case vintf::Arch::ARCH_32_64:
             return sStrBoth;
-        case ARCH_UNKNOWN: // fall through
+        case vintf::Arch::ARCH_EMPTY: // fall through
         default:
             return sStrUnknown;
     }
@@ -57,6 +61,8 @@
         case TableColumnType::THREADS:          return "Thread Use";
         case TableColumnType::RELEASED:         return "R";
         case TableColumnType::HASH:             return "Hash";
+        case TableColumnType::VINTF:            return "VINTF";
+        case TableColumnType::SERVICE_STATUS:   return "Status";
         default:
             LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
             return "";
@@ -68,7 +74,7 @@
         case TableColumnType::INTERFACE_NAME:
             return interfaceName;
         case TableColumnType::TRANSPORT:
-            return transport;
+            return vintf::to_string(transport);
         case TableColumnType::SERVER_PID:
             return serverPid == NO_PID ? "N/A" : std::to_string(serverPid);
         case TableColumnType::SERVER_CMD:
@@ -87,6 +93,10 @@
             return isReleased();
         case TableColumnType::HASH:
             return hash;
+        case TableColumnType::VINTF:
+            return getVintfInfo();
+        case TableColumnType::SERVICE_STATUS:
+            return lshal::to_string(serviceStatus);
         default:
             LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
             return "";
@@ -96,12 +106,44 @@
 std::string TableEntry::isReleased() const {
     static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
 
-    if (hash.empty() || hash == unreleased) {
-        return " "; // unknown or unreleased
+    if (hash.empty()) {
+        return "?";
+    }
+    if (hash == unreleased) {
+        return "N"; // unknown or unreleased
     }
     return "Y"; // released
 }
 
+std::string TableEntry::getVintfInfo() const {
+    static const std::map<VintfInfo, std::string> values{
+            {DEVICE_MANIFEST, "DM"},
+            {DEVICE_MATRIX, "DC"},
+            {FRAMEWORK_MANIFEST, "FM"},
+            {FRAMEWORK_MATRIX, "FC"},
+    };
+    std::vector<std::string> ret;
+    for (const auto& pair : values) {
+        if (vintfInfo & pair.first) {
+            ret.push_back(pair.second);
+        }
+    }
+    auto joined = base::Join(ret, ',');
+    return joined.empty() ? "X" : joined;
+}
+
+std::string to_string(ServiceStatus s) {
+    switch (s) {
+        case ServiceStatus::ALIVE: return "alive";
+        case ServiceStatus::NON_RESPONSIVE: return "non-responsive";
+        case ServiceStatus::DECLARED: return "declared";
+        case ServiceStatus::UNKNOWN: return "N/A";
+    }
+
+    LOG(FATAL) << __func__ << "Should not reach here." << static_cast<int>(s);
+    return "";
+}
+
 TextTable Table::createTextTable(bool neat,
     const std::function<std::string(const std::string&)>& emitDebugInfo) const {
 
@@ -152,6 +194,7 @@
 }
 
 std::string TableEntry::to_string() const {
+    using vintf::operator<<;
     std::stringstream ss;
     ss << "name=" << interfaceName << ";transport=" << transport << ";thread=" << getThreadUsage()
        << ";server=" << serverPid
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 24ea438..601b7e2 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -24,6 +24,8 @@
 #include <iostream>
 
 #include <procpartition/procpartition.h>
+#include <vintf/Arch.h>
+#include <vintf/Transport.h>
 
 #include "TextTable.h"
 
@@ -33,21 +35,6 @@
 using android::procpartition::Partition;
 using Pids = std::vector<int32_t>;
 
-enum : unsigned int {
-    HWSERVICEMANAGER_LIST, // through defaultServiceManager()->list()
-    PTSERVICEMANAGER_REG_CLIENT, // through registerPassthroughClient
-    LIST_DLLIB, // through listing dynamic libraries
-};
-using TableEntrySource = unsigned int;
-
-enum : unsigned int {
-    ARCH_UNKNOWN = 0,
-    ARCH32       = 1 << 0,
-    ARCH64       = 1 << 1,
-    ARCH_BOTH    = ARCH32 | ARCH64
-};
-using Architecture = unsigned int;
-
 enum class TableColumnType : unsigned int {
     INTERFACE_NAME,
     TRANSPORT,
@@ -60,16 +47,35 @@
     THREADS,
     RELEASED,
     HASH,
+    VINTF,
+    SERVICE_STATUS,
 };
 
+enum : unsigned int {
+    VINTF_INFO_EMPTY = 0,
+    DEVICE_MANIFEST = 1 << 0,
+    DEVICE_MATRIX = 1 << 1,
+    FRAMEWORK_MANIFEST = 1 << 2,
+    FRAMEWORK_MATRIX = 1 << 3,
+};
+using VintfInfo = unsigned int;
+
 enum {
     NO_PID = -1,
     NO_PTR = 0
 };
 
+enum class ServiceStatus {
+    UNKNOWN, // For passthrough
+    ALIVE,
+    NON_RESPONSIVE, // registered but not respond to calls
+    DECLARED, // in VINTF manifest
+};
+std::string to_string(ServiceStatus s);
+
 struct TableEntry {
     std::string interfaceName{};
-    std::string transport{};
+    vintf::Transport transport{vintf::Transport::EMPTY};
     int32_t serverPid{NO_PID};
     uint32_t threadUsage{0};
     uint32_t threadCount{0};
@@ -77,10 +83,13 @@
     uint64_t serverObjectAddress{NO_PTR};
     Pids clientPids{};
     std::vector<std::string> clientCmdlines{};
-    Architecture arch{ARCH_UNKNOWN};
+    vintf::Arch arch{vintf::Arch::ARCH_EMPTY};
     // empty: unknown, all zeros: unreleased, otherwise: released
     std::string hash{};
     Partition partition{Partition::UNKNOWN};
+    VintfInfo vintfInfo{VINTF_INFO_EMPTY};
+    // true iff hwbinder and service started
+    ServiceStatus serviceStatus{ServiceStatus::UNKNOWN};
 
     static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
         return a.interfaceName < b.interfaceName;
@@ -99,6 +108,8 @@
 
     std::string isReleased() const;
 
+    std::string getVintfInfo() const;
+
     std::string getField(TableColumnType type) const;
 
     bool operator==(const TableEntry& other) const;
@@ -138,7 +149,7 @@
 
 class MergedTable {
 public:
-    MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
+    explicit MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
     TextTable createTextTable();
 private:
     std::vector<const Table*> mTables;
diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h
index 91d522a..301b4bd 100644
--- a/cmds/lshal/TextTable.h
+++ b/cmds/lshal/TextTable.h
@@ -33,11 +33,11 @@
     TextTableRow() {}
 
     // A row of cells.
-    TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
+    explicit TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
 
     // A single comment string.
-    TextTableRow(std::string&& s) : mLine(std::move(s)) {}
-    TextTableRow(const std::string& s) : mLine(s) {}
+    explicit TextTableRow(std::string&& s) : mLine(std::move(s)) {}
+    explicit TextTableRow(const std::string& s) : mLine(s) {}
 
     // Whether this row is an actual row of cells.
     bool isRow() const { return !fields().empty(); }
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index c940404..46d8177 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -29,7 +29,7 @@
 
 class BackgroundTaskState {
 public:
-    BackgroundTaskState(std::function<void(void)> &&func)
+    explicit BackgroundTaskState(std::function<void(void)> &&func)
             : mFunc(std::forward<decltype(func)>(func)) {}
     void notify() {
         std::unique_lock<std::mutex> lock(mMutex);
@@ -57,7 +57,7 @@
     BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
     state();
     state.notify();
-    return NULL;
+    return nullptr;
 }
 
 template<class R, class P>
@@ -65,7 +65,7 @@
     auto now = std::chrono::system_clock::now();
     BackgroundTaskState state{std::forward<decltype(func)>(func)};
     pthread_t thread;
-    if (pthread_create(&thread, NULL, callAndNotify, &state)) {
+    if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
         std::cerr << "FATAL: could not create background thread." << std::endl;
         return false;
     }
@@ -73,7 +73,7 @@
     if (!success) {
         pthread_kill(thread, SIGINT);
     }
-    pthread_join(thread, NULL);
+    pthread_join(thread, nullptr);
     return success;
 }
 
diff --git a/cmds/lshal/libprocpartition/procpartition.cpp b/cmds/lshal/libprocpartition/procpartition.cpp
index 8ca458a..9645f3a 100644
--- a/cmds/lshal/libprocpartition/procpartition.cpp
+++ b/cmds/lshal/libprocpartition/procpartition.cpp
@@ -50,7 +50,7 @@
                                          false /* follow symlinks */)) {
         return "";
     }
-    return content;
+    return std::string{content.c_str()};
 }
 
 Partition parsePartition(const std::string& s) {
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 4fa941e..fc8d58b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -44,6 +44,13 @@
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using android::vintf::Arch;
+using android::vintf::CompatibilityMatrix;
+using android::vintf::gCompatibilityMatrixConverter;
+using android::vintf::gHalManifestConverter;
+using android::vintf::HalManifest;
+using android::vintf::Transport;
+using android::vintf::VintfObject;
 
 using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
 
@@ -184,7 +191,7 @@
 // expose protected fields and methods for ListCommand
 class MockListCommand : public ListCommand {
 public:
-    MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
+    explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
 
     Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
     Status main(const Arg& arg) { return ListCommand::main(arg); }
@@ -207,6 +214,11 @@
     MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
     MOCK_METHOD1(getPartition, Partition(pid_t));
+
+    MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
+    MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
+    MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
+    MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
 };
 
 class ListParseArgsTest : public ::testing::Test {
@@ -214,12 +226,13 @@
     void SetUp() override {
         mockLshal = std::make_unique<NiceMock<MockLshal>>();
         mockList = std::make_unique<MockListCommand>(mockLshal.get());
+        ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
         // ListCommand::parseArgs should parse arguments from the second element
         optind = 1;
     }
     std::unique_ptr<MockLshal> mockLshal;
     std::unique_ptr<MockListCommand> mockList;
-    std::stringstream output;
+    std::stringstream err;
 };
 
 TEST_F(ListParseArgsTest, Args) {
@@ -229,6 +242,7 @@
                                    TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
                   table.getSelectedColumns());
     });
+    EXPECT_EQ("", err.str());
 }
 
 TEST_F(ListParseArgsTest, Cmds) {
@@ -243,12 +257,12 @@
         EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
                 << "should print client cmds with -m";
     });
+    EXPECT_EQ("", err.str());
 }
 
 TEST_F(ListParseArgsTest, DebugAndNeat) {
-    ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
     EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
-    EXPECT_THAT(output.str(), StrNe(""));
+    EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
 }
 
 /// Fetch Test
@@ -294,7 +308,7 @@
 // Fake service returned by mocked IServiceManager::get.
 class TestService : public IBase {
 public:
-    TestService(pid_t id) : mId(id) {}
+    explicit TestService(pid_t id) : mId(id) {}
     hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
         cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
         return hardware::Void();
@@ -313,7 +327,7 @@
 
 class ListTest : public ::testing::Test {
 public:
-    void SetUp() override {
+    virtual void SetUp() override {
         initMockServiceManager();
         lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
         initMockList();
@@ -335,6 +349,15 @@
             });
         }));
         ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
+
+        ON_CALL(*mockList, getDeviceManifest())
+                .WillByDefault(Return(std::make_shared<HalManifest>()));
+        ON_CALL(*mockList, getDeviceMatrix())
+                .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
+        ON_CALL(*mockList, getFrameworkManifest())
+                .WillByDefault(Return(std::make_shared<HalManifest>()));
+        ON_CALL(*mockList, getFrameworkMatrix())
+                .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
     }
 
     void initMockServiceManager() {
@@ -388,92 +411,76 @@
 }
 
 TEST_F(ListTest, Fetch) {
-    EXPECT_EQ(0u, mockList->fetch());
-    std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
-                                          "passthrough", "passthrough", "passthrough"}};
-    std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
-    int id = 1;
+    optind = 1; // mimic Lshal::parseArg()
+    ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
+    ASSERT_EQ(0u, mockList->fetch());
+    vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
+    vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
+    std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
+                                                        passthrough, passthrough, passthrough}};
+    int i = 0;
     mockList->forEachTable([&](const Table& table) {
-        ASSERT_EQ(2u, table.size());
         for (const auto& entry : table) {
-            const auto& transport = transports[id - 1];
+            if (i >= transportArchs.size()) {
+                break;
+            }
+
+            int id = i + 1;
+            auto transport = transportArchs.at(i).transport;
             TableEntry expected{
                 .interfaceName = getFqInstanceName(id),
                 .transport = transport,
-                .serverPid = transport == "hwbinder" ? id : NO_PID,
-                .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
-                .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
+                .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
+                .threadUsage =
+                        transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
+                .threadCount =
+                        transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
                 .serverCmdline = {},
-                .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
+                .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
                 .clientPids = getClients(id),
                 .clientCmdlines = {},
-                .arch = archs[id - 1],
+                .arch = transportArchs.at(i).arch,
             };
             EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
 
-            ++id;
+            ++i;
         }
     });
 
+    EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
+
 }
 
 TEST_F(ListTest, DumpVintf) {
-    const std::string expected =
-        "<!-- \n"
-        "    This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
-        "-->\n"
-        "<manifest version=\"1.0\" type=\"device\">\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>a.h.foo1</name>\n"
-        "        <transport>hwbinder</transport>\n"
-        "        <version>1.0</version>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>1</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>a.h.foo2</name>\n"
-        "        <transport>hwbinder</transport>\n"
-        "        <version>2.0</version>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>2</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>a.h.foo3</name>\n"
-        "        <transport arch=\"32\">passthrough</transport>\n"
-        "        <version>3.0</version>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>3</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>a.h.foo4</name>\n"
-        "        <transport arch=\"32\">passthrough</transport>\n"
-        "        <version>4.0</version>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>4</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>a.h.foo5</name>\n"
-        "        <transport arch=\"32\">passthrough</transport>\n"
-        "        <version>5.0</version>\n"
-        "    </hal>\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>a.h.foo6</name>\n"
-        "        <transport arch=\"32\">passthrough</transport>\n"
-        "        <version>6.0</version>\n"
-        "    </hal>\n"
-        "</manifest>\n";
+    const std::string expected = "<manifest version=\"1.0\" type=\"device\">\n"
+                                 "    <hal format=\"hidl\">\n"
+                                 "        <name>a.h.foo1</name>\n"
+                                 "        <transport>hwbinder</transport>\n"
+                                 "        <fqname>@1.0::IFoo/1</fqname>\n"
+                                 "    </hal>\n"
+                                 "    <hal format=\"hidl\">\n"
+                                 "        <name>a.h.foo2</name>\n"
+                                 "        <transport>hwbinder</transport>\n"
+                                 "        <fqname>@2.0::IFoo/2</fqname>\n"
+                                 "    </hal>\n"
+                                 "    <hal format=\"hidl\">\n"
+                                 "        <name>a.h.foo3</name>\n"
+                                 "        <transport arch=\"32\">passthrough</transport>\n"
+                                 "        <fqname>@3.0::IFoo/3</fqname>\n"
+                                 "    </hal>\n"
+                                 "    <hal format=\"hidl\">\n"
+                                 "        <name>a.h.foo4</name>\n"
+                                 "        <transport arch=\"32\">passthrough</transport>\n"
+                                 "        <fqname>@4.0::IFoo/4</fqname>\n"
+                                 "    </hal>\n"
+                                 "</manifest>";
 
     optind = 1; // mimic Lshal::parseArg()
     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
-    EXPECT_EQ(expected, out.str());
+    auto output = out.str();
+    EXPECT_THAT(output, HasSubstr(expected));
+    EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
+    EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
     EXPECT_EQ("", err.str());
 
     vintf::HalManifest m;
@@ -487,18 +494,18 @@
     const std::string expected =
         "[fake description 0]\n"
         "R Interface            Thread Use Server Clients\n"
-        "  a.h.foo1@1.0::IFoo/1 11/21      1      2 4\n"
+        "N a.h.foo1@1.0::IFoo/1 11/21      1      2 4\n"
         "Y a.h.foo2@2.0::IFoo/2 12/22      2      3 5\n"
         "\n"
         "[fake description 1]\n"
         "R Interface            Thread Use Server Clients\n"
-        "  a.h.foo3@3.0::IFoo/3 N/A        N/A    4 6\n"
-        "  a.h.foo4@4.0::IFoo/4 N/A        N/A    5 7\n"
+        "? a.h.foo3@3.0::IFoo/3 N/A        N/A    4 6\n"
+        "? a.h.foo4@4.0::IFoo/4 N/A        N/A    5 7\n"
         "\n"
         "[fake description 2]\n"
         "R Interface            Thread Use Server Clients\n"
-        "  a.h.foo5@5.0::IFoo/5 N/A        N/A    6 8\n"
-        "  a.h.foo6@6.0::IFoo/6 N/A        N/A    7 9\n"
+        "? a.h.foo5@5.0::IFoo/5 N/A        N/A    6 8\n"
+        "? a.h.foo6@6.0::IFoo/6 N/A        N/A    7 9\n"
         "\n";
 
     optind = 1; // mimic Lshal::parseArg()
@@ -511,18 +518,18 @@
     const std::string expected =
         "[fake description 0]\n"
         "Interface            R Hash\n"
-        "a.h.foo1@1.0::IFoo/1   0000000000000000000000000000000000000000000000000000000000000000\n"
+        "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
         "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
         "\n"
         "[fake description 1]\n"
         "Interface            R Hash\n"
-        "a.h.foo3@3.0::IFoo/3   \n"
-        "a.h.foo4@4.0::IFoo/4   \n"
+        "a.h.foo3@3.0::IFoo/3 ? \n"
+        "a.h.foo4@4.0::IFoo/4 ? \n"
         "\n"
         "[fake description 2]\n"
         "Interface            R Hash\n"
-        "a.h.foo5@5.0::IFoo/5   \n"
-        "a.h.foo6@6.0::IFoo/6   \n"
+        "a.h.foo5@5.0::IFoo/5 ? \n"
+        "a.h.foo6@6.0::IFoo/6 ? \n"
         "\n";
 
     optind = 1; // mimic Lshal::parseArg()
@@ -594,6 +601,225 @@
     EXPECT_EQ("", err.str());
 }
 
+TEST_F(ListTest, DumpSingleHalType) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport Arch Thread Use Server PTR              Clients\n"
+        "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
+        "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpReorderedHalTypes) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
+        "\n"
+        "[fake description 2]\n"
+        "Interface            Transport Arch Thread Use Server PTR              Clients\n"
+        "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
+        "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
+                                            "--types=passthrough_libs", "--types=binderized"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpAbbreviatedHalTypes) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Arch Thread Use Server PTR Clients\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
+        "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
+                                            "--types=passthrough_libs,passthrough_clients"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, UnknownHalType) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,a"})));
+    EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: a"));
+}
+
+TEST_F(ListTest, Vintf) {
+    std::string deviceManifestXml =
+            "<manifest version=\"1.0\" type=\"device\">\n"
+            "    <hal>\n"
+            "        <name>a.h.foo1</name>\n"
+            "        <transport>hwbinder</transport>\n"
+            "        <fqname>@1.0::IFoo/1</fqname>\n"
+            "    </hal>\n"
+            "    <hal>\n"
+            "        <name>a.h.foo3</name>\n"
+            "        <transport arch=\"32+64\">passthrough</transport>\n"
+            "        <fqname>@3.0::IFoo/3</fqname>\n"
+            "    </hal>\n"
+            "</manifest>\n";
+    std::string frameworkManifestXml =
+            "<manifest version=\"1.0\" type=\"framework\">\n"
+            "    <hal>\n"
+            "        <name>a.h.foo5</name>\n"
+            "        <transport arch=\"32\">passthrough</transport>\n"
+            "        <fqname>@5.0::IFoo/5</fqname>\n"
+            "    </hal>\n"
+            "</manifest>\n";
+    std::string deviceMatrixXml =
+            "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
+            "    <hal>\n"
+            "        <name>a.h.foo5</name>\n"
+            "        <version>5.0</version>\n"
+            "        <interface>\n"
+            "            <name>IFoo</name>\n"
+            "            <instance>5</instance>\n"
+            "        </interface>\n"
+            "    </hal>\n"
+            "</compatibility-matrix>\n";
+    std::string frameworkMatrixXml =
+            "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+            "    <hal>\n"
+            "        <name>a.h.foo1</name>\n"
+            "        <version>1.0</version>\n"
+            "        <interface>\n"
+            "            <name>IFoo</name>\n"
+            "            <instance>1</instance>\n"
+            "        </interface>\n"
+            "    </hal>\n"
+            "    <hal>\n"
+            "        <name>a.h.foo3</name>\n"
+            "        <version>3.0</version>\n"
+            "        <interface>\n"
+            "            <name>IFoo</name>\n"
+            "            <instance>3</instance>\n"
+            "        </interface>\n"
+            "    </hal>\n"
+            "</compatibility-matrix>\n";
+
+    std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
+                           "X     a.h.foo2@2.0::IFoo/2\n"
+                           "DM,FC a.h.foo3@3.0::IFoo/3\n"
+                           "X     a.h.foo4@4.0::IFoo/4\n"
+                           "DC,FM a.h.foo5@5.0::IFoo/5\n"
+                           "X     a.h.foo6@6.0::IFoo/6\n";
+
+    auto deviceManifest = std::make_shared<HalManifest>();
+    auto frameworkManifest = std::make_shared<HalManifest>();
+    auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
+    auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
+
+    ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
+    ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
+    ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
+    ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
+
+    ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
+    ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
+    ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
+    ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
+    EXPECT_THAT(out.str(), HasSubstr(expected));
+    EXPECT_EQ("", err.str());
+}
+
+class ListVintfTest : public ListTest {
+public:
+    virtual void SetUp() override {
+        ListTest::SetUp();
+        const std::string mockManifestXml =
+                "<manifest version=\"1.0\" type=\"device\">\n"
+                "    <hal format=\"hidl\">\n"
+                "        <name>a.h.foo1</name>\n"
+                "        <transport>hwbinder</transport>\n"
+                "        <fqname>@1.0::IFoo/1</fqname>\n"
+                "    </hal>\n"
+                "    <hal format=\"hidl\">\n"
+                "        <name>a.h.bar1</name>\n"
+                "        <transport>hwbinder</transport>\n"
+                "        <fqname>@1.0::IBar/1</fqname>\n"
+                "    </hal>\n"
+                "    <hal format=\"hidl\">\n"
+                "        <name>a.h.bar2</name>\n"
+                "        <transport arch=\"32+64\">passthrough</transport>\n"
+                "        <fqname>@2.0::IBar/2</fqname>\n"
+                "    </hal>\n"
+                "</manifest>";
+        auto manifest = std::make_shared<HalManifest>();
+        EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
+        EXPECT_CALL(*mockList, getDeviceManifest())
+            .Times(AnyNumber())
+            .WillRepeatedly(Return(manifest));
+    }
+};
+
+TEST_F(ListVintfTest, ManifestHals) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder    ?"));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.foo1@1.0::IFoo/1 declared hwbinder    ?"));
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListVintfTest, Lazy) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder    ?"));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListVintfTest, NoLazy) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
+    EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
+    EXPECT_EQ("", err.str());
+}
+
 class HelpTest : public ::testing::Test {
 public:
     void SetUp() override {
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index c09e8b1..240155e 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -46,6 +46,8 @@
     TRANSACTION_ERROR                       = 1 << 8,
     // No transaction error, but return value is unexpected.
     BAD_IMPL                                = 1 << 9,
+    // Cannot fetch VINTF data.
+    VINTF_ERROR                             = 1 << 10,
 };
 using Status = unsigned int;
 
diff --git a/cmds/rawbu/Android.bp b/cmds/rawbu/Android.bp
new file mode 100644
index 0000000..363ffc1
--- /dev/null
+++ b/cmds/rawbu/Android.bp
@@ -0,0 +1,14 @@
+// Copyright 2009 The Android Open Source Project
+
+cc_binary {
+    name: "rawbu",
+
+    srcs: ["backup.cpp"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: ["libcutils"],
+}
diff --git a/cmds/rawbu/Android.mk b/cmds/rawbu/Android.mk
deleted file mode 100644
index 9322151..0000000
--- a/cmds/rawbu/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2009 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= backup.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := libcutils libc
-
-LOCAL_MODULE:= rawbu
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index 0072281..8b20e3e 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -38,7 +38,7 @@
 static struct stat statBuffer;
 
 static char copyBuffer[8192];
-static char *backupFilePath = NULL;
+static char *backupFilePath = nullptr;
 
 static uint32_t inputFileVersion;
 
@@ -58,7 +58,7 @@
     { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH },
     { "/data/system/location", SPECIAL_NO_TOUCH },
     { "/data/dalvik-cache", SPECIAL_NO_BACKUP },
-    { NULL, 0 },
+    { nullptr, 0 },
 };
 
 /* This is just copied from the shell's built-in wipe command. */
@@ -71,7 +71,7 @@
 
     dir = opendir(path);
 
-    if (dir == NULL) {
+    if (dir == nullptr) {
         fprintf (stderr, "Error opendir'ing %s: %s\n",
                     path, strerror(errno));
         return 0;
@@ -87,7 +87,7 @@
     for (;;) {
         de = readdir(dir);
 
-        if (de == NULL) {
+        if (de == nullptr) {
             break;
         }
 
@@ -115,7 +115,7 @@
             }
         }
         
-        if (!noBackup && SKIP_PATHS[i].path != NULL) {
+        if (!noBackup && SKIP_PATHS[i].path != nullptr) {
             // This is a SPECIAL_NO_TOUCH directory.
             continue;
         }
@@ -203,7 +203,7 @@
         int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size;
         int readLen = fread(copyBuffer, 1, amt, src);
         if (readLen <= 0) {
-            if (srcName != NULL) {
+            if (srcName != nullptr) {
                 fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n",
                     amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF");
             } else {
@@ -214,7 +214,7 @@
         }
         int writeLen = fwrite(copyBuffer, 1, readLen, dest); 
         if (writeLen != readLen) {
-            if (destName != NULL) {
+            if (destName != nullptr) {
                 fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n",
                     writeLen, readLen, destName, strerror(errno));
             } else {
@@ -256,14 +256,14 @@
 {
     DIR *dir;
     struct dirent *de;
-    char* fullPath = NULL;
+    char* fullPath = nullptr;
     int srcLen = strlen(srcPath);
     int result = 1;
     int i;
     
     dir = opendir(srcPath);
 
-    if (dir == NULL) {
+    if (dir == nullptr) {
         fprintf (stderr, "error opendir'ing '%s': %s\n",
                     srcPath, strerror(errno));
         return 0;
@@ -272,7 +272,7 @@
     for (;;) {
         de = readdir(dir);
 
-        if (de == NULL) {
+        if (de == nullptr) {
             break;
         }
 
@@ -283,7 +283,7 @@
             continue;
         }
 
-        if (fullPath != NULL) {
+        if (fullPath != nullptr) {
             free(fullPath);
         }
         fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2);
@@ -298,7 +298,7 @@
                     break;
                 }
             }
-            if (SKIP_PATHS[i].path != NULL) {
+            if (SKIP_PATHS[i].path != nullptr) {
                 continue;
             }
         }
@@ -343,14 +343,14 @@
             }
             
             FILE* src = fopen(fullPath, "r");
-            if (src == NULL) {
+            if (src == nullptr) {
                 fprintf(stderr, "unable to open source file '%s': %s\n",
                     fullPath, strerror(errno));
                 result = 0;
                 goto done;
             }
             
-            int copyres = copy_file(fh, src, size, NULL, fullPath);
+            int copyres = copy_file(fh, src, size, nullptr, fullPath);
             fclose(src);
             if (!copyres) {
                 result = 0;
@@ -360,7 +360,7 @@
     }
 
 done:
-    if (fullPath != NULL) {
+    if (fullPath != nullptr) {
         free(fullPath);
     }
     
@@ -374,7 +374,7 @@
     int res = -1;
     
     FILE* fh = fopen(destPath, "w");
-    if (fh == NULL) {
+    if (fh == nullptr) {
         fprintf(stderr, "unable to open destination '%s': %s\n",
                 destPath, strerror(errno));
         return -1;
@@ -504,7 +504,7 @@
     int res = -1;
     
     FILE* fh = fopen(srcPath, "r");
-    if (fh == NULL) {
+    if (fh == nullptr) {
         fprintf(stderr, "Unable to open source '%s': %s\n",
                 srcPath, strerror(errno));
         return -1;
@@ -534,7 +534,7 @@
 
     while (1) {
         int type;
-        char* path = NULL;
+        char* path = nullptr;
         if (read_header(fh, &type, &path, &statBuffer) == 0) {
             goto done;
         }
@@ -570,14 +570,14 @@
             printf("Restoring file %s...\n", path);
             
             FILE* dest = fopen(path, "w");
-            if (dest == NULL) {
+            if (dest == nullptr) {
                 fprintf(stderr, "unable to open destination file '%s': %s\n",
                     path, strerror(errno));
                 free(path);
                 goto done;
             }
             
-            int copyres = copy_file(dest, fh, size, path, NULL);
+            int copyres = copy_file(dest, fh, size, path, nullptr);
             fclose(dest);
             if (!copyres) {
                 free(path);
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
new file mode 100644
index 0000000..15f10ef
--- /dev/null
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://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.
+
+cc_binary {
+    name: "rss_hwm_reset",
+
+    srcs: [
+        "rss_hwm_reset.cc",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    init_rc: ["rss_hwm_reset.rc"],
+}
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.cc b/cmds/rss_hwm_reset/rss_hwm_reset.cc
new file mode 100644
index 0000000..1626e7e
--- /dev/null
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://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.
+ */
+
+ /*
+  * rss_hwm_reset clears the RSS high-water mark counters for all currently
+  * running processes. It writes "5" to /proc/PID/clear_refs for every PID.
+  *
+  * It runs in its own process becuase dac_override capability is required
+  * in order to write to other processes' clear_refs.
+  *
+  * It is invoked from a system service by flipping sys.rss_hwm_reset.on
+  * property to "1".
+  */
+
+#define LOG_TAG "rss_hwm_reset"
+
+#include <dirent.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+
+namespace {
+// Resets RSS HWM counter for the selected process by writing 5 to
+// /proc/PID/clear_refs.
+void reset_rss_hwm(const char* pid) {
+    std::string clear_refs_path =
+            ::android::base::StringPrintf("/proc/%s/clear_refs", pid);
+    ::android::base::WriteStringToFile("5", clear_refs_path);
+}
+}
+
+// Clears RSS HWM counters for all currently running processes.
+int main(int /* argc */, char** /* argv[] */) {
+    DIR* dirp = opendir("/proc");
+    if (dirp == nullptr) {
+        ALOGE("unable to read /proc");
+        return 1;
+    }
+    struct dirent* entry;
+    while ((entry = readdir(dirp)) != nullptr) {
+        // Skip entries that are not directories.
+        if (entry->d_type != DT_DIR) continue;
+        // Skip entries that do not contain only numbers.
+        const char* pid = entry->d_name;
+        while (*pid) {
+            if (*pid < '0' || *pid > '9') break;
+            pid++;
+        }
+        if (*pid != 0) continue;
+
+        pid = entry->d_name;
+        reset_rss_hwm(pid);
+    }
+    closedir(dirp);
+    return 0;
+}
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.rc b/cmds/rss_hwm_reset/rss_hwm_reset.rc
new file mode 100644
index 0000000..fbbc820
--- /dev/null
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.rc
@@ -0,0 +1,26 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://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.
+
+service rss_hwm_reset /system/bin/rss_hwm_reset
+    class late_start
+    disabled
+    oneshot
+    user nobody
+    group nobody readproc
+    writepid /dev/cpuset/system-background/tasks
+    capabilities DAC_OVERRIDE
+
+on property:sys.rss_hwm_reset.on=1
+    start rss_hwm_reset
+    setprop sys.rss_hwm_reset.on 0
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index bc11256..d5dc6b7 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -30,7 +30,7 @@
 
 void writeString16(Parcel& parcel, const char* string)
 {
-    if (string != NULL)
+    if (string != nullptr)
     {
         parcel.writeString16(String16(string));
     }
@@ -43,7 +43,7 @@
 // get the name of the generic interface we hold a reference to
 static String16 get_interface_name(sp<IBinder> service)
 {
-    if (service != NULL) {
+    if (service != nullptr) {
         Parcel data, reply;
         status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
         if (err == NO_ERROR) {
@@ -93,7 +93,7 @@
 #endif
     sp<IServiceManager> sm = defaultServiceManager();
     fflush(stdout);
-    if (sm == NULL) {
+    if (sm == nullptr) {
         aerr << "service: Unable to get default service manager!" << endl;
         return 20;
     }
@@ -106,7 +106,7 @@
             if (optind < argc) {
                 sp<IBinder> service = sm->checkService(String16(argv[optind]));
                 aout << "Service " << argv[optind] <<
-                    (service == NULL ? ": not found" : ": found") << endl;
+                    (service == nullptr ? ": not found" : ": found") << endl;
             } else {
                 aerr << "service: No service specified for check" << endl;
                 wantsUsage = true;
@@ -131,7 +131,7 @@
                 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
                 String16 ifName = get_interface_name(service);
                 int32_t code = atoi(argv[optind++]);
-                if (service != NULL && ifName.size() > 0) {
+                if (service != nullptr && ifName.size() > 0) {
                     Parcel data, reply;
 
                     // the interface name is first
@@ -186,28 +186,28 @@
                             data.writeDouble(atof(argv[optind++]));
                         } else if (strcmp(argv[optind], "null") == 0) {
                             optind++;
-                            data.writeStrongBinder(NULL);
+                            data.writeStrongBinder(nullptr);
                         } else if (strcmp(argv[optind], "intent") == 0) {
                         	
-                        	char* action = NULL;
-                        	char* dataArg = NULL;
-                        	char* type = NULL;
+                        	char* action = nullptr;
+                        	char* dataArg = nullptr;
+                        	char* type = nullptr;
                         	int launchFlags = 0;
-                        	char* component = NULL;
+                        	char* component = nullptr;
                         	int categoryCount = 0;
                         	char* categories[16];
                         	
-                        	char* context1 = NULL;
+                        	char* context1 = nullptr;
                         	
                             optind++;
                             
                         	while (optind < argc)
                         	{
                         		char* key = strtok_r(argv[optind], "=", &context1);
-                        		char* value = strtok_r(NULL, "=", &context1);
+                        		char* value = strtok_r(nullptr, "=", &context1);
                                 
                                 // we have reached the end of the XXX=XXX args.
-                                if (key == NULL) break;
+                                if (key == nullptr) break;
                         		
                         		if (strcmp(key, "action") == 0)
                         		{
@@ -231,14 +231,13 @@
                         		}
                         		else if (strcmp(key, "categories") == 0)
                         		{
-                        			char* context2 = NULL;
-                        			int categoryCount = 0;
+                        			char* context2 = nullptr;
                         			categories[categoryCount] = strtok_r(value, ",", &context2);
                         			
-                        			while (categories[categoryCount] != NULL)
+                        			while (categories[categoryCount] != nullptr)
                         			{
                         				categoryCount++;
-                        				categories[categoryCount] = strtok_r(NULL, ",", &context2);
+                        				categories[categoryCount] = strtok_r(nullptr, ",", &context2);
                         			}
                         		}
                                 
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index fade8cf..cf3b172 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -146,7 +146,19 @@
 
 int binder_become_context_manager(struct binder_state *bs)
 {
-    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
+    struct flat_binder_object obj;
+    memset(&obj, 0, sizeof(obj));
+    obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+
+    int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
+
+    // fallback to original method
+    if (result != 0) {
+        android_errorWriteLog(0x534e4554, "121035042");
+
+        result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
+    }
+    return result;
 }
 
 int binder_write(struct binder_state *bs, void *data, size_t len)
@@ -240,13 +252,28 @@
 #endif
             ptr += sizeof(struct binder_ptr_cookie);
             break;
+        case BR_TRANSACTION_SEC_CTX:
         case BR_TRANSACTION: {
-            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
-            if ((end - ptr) < sizeof(*txn)) {
-                ALOGE("parse: txn too small!\n");
-                return -1;
+            struct binder_transaction_data_secctx txn;
+            if (cmd == BR_TRANSACTION_SEC_CTX) {
+                if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) {
+                    ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n");
+                    return -1;
+                }
+                memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx));
+                ptr += sizeof(struct binder_transaction_data_secctx);
+            } else /* BR_TRANSACTION */ {
+                if ((end - ptr) < sizeof(struct binder_transaction_data)) {
+                    ALOGE("parse: txn too small (binder_transaction_data)!\n");
+                    return -1;
+                }
+                memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data));
+                ptr += sizeof(struct binder_transaction_data);
+
+                txn.secctx = 0;
             }
-            binder_dump_txn(txn);
+
+            binder_dump_txn(&txn.transaction_data);
             if (func) {
                 unsigned rdata[256/4];
                 struct binder_io msg;
@@ -254,15 +281,14 @@
                 int res;
 
                 bio_init(&reply, rdata, sizeof(rdata), 4);
-                bio_init_from_txn(&msg, txn);
-                res = func(bs, txn, &msg, &reply);
-                if (txn->flags & TF_ONE_WAY) {
-                    binder_free_buffer(bs, txn->data.ptr.buffer);
+                bio_init_from_txn(&msg, &txn.transaction_data);
+                res = func(bs, &txn, &msg, &reply);
+                if (txn.transaction_data.flags & TF_ONE_WAY) {
+                    binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
                 } else {
-                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
+                    binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
                 }
             }
-            ptr += sizeof(*txn);
             break;
         }
         case BR_REPLY: {
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index c95b33f..a9ccc74 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -4,8 +4,8 @@
 #ifndef _BINDER_H_
 #define _BINDER_H_
 
-#include <sys/ioctl.h>
 #include <linux/android/binder.h>
+#include <sys/ioctl.h>
 
 struct binder_state;
 
@@ -42,7 +42,7 @@
 };
 
 typedef int (*binder_handler)(struct binder_state *bs,
-                              struct binder_transaction_data *txn,
+                              struct binder_transaction_data_secctx *txn,
                               struct binder_io *msg,
                               struct binder_io *reply);
 
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 6b340a8..ec3fac5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -61,14 +61,14 @@
 static char *service_manager_context;
 static struct selabel_handle* sehandle;
 
-static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
+static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name)
 {
-    char *sctx = NULL;
+    char *lookup_sid = NULL;
     const char *class = "service_manager";
     bool allowed;
     struct audit_data ad;
 
-    if (getpidcon(spid, &sctx) < 0) {
+    if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) {
         ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
         return false;
     }
@@ -77,19 +77,23 @@
     ad.uid = uid;
     ad.name = name;
 
-    int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
+    if (sid == NULL) {
+        android_errorWriteLog(0x534e4554, "121035042");
+    }
+
+    int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad);
     allowed = (result == 0);
 
-    freecon(sctx);
+    freecon(lookup_sid);
     return allowed;
 }
 
-static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
+static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm)
 {
-    return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
+    return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL);
 }
 
-static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
+static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name)
 {
     bool allowed;
     char *tctx = NULL;
@@ -104,12 +108,12 @@
         return false;
     }
 
-    allowed = check_mac_perms(spid, uid, tctx, perm, name);
+    allowed = check_mac_perms(spid, sid, uid, tctx, perm, name);
     freecon(tctx);
     return allowed;
 }
 
-static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
+static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
 {
     const char *perm = "add";
 
@@ -117,19 +121,19 @@
         return 0; /* Don't allow apps to register services */
     }
 
-    return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
+    return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
 }
 
-static int svc_can_list(pid_t spid, uid_t uid)
+static int svc_can_list(pid_t spid, const char* sid, uid_t uid)
 {
     const char *perm = "list";
-    return check_mac_perms_from_getcon(spid, uid, perm) ? 1 : 0;
+    return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0;
 }
 
-static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
+static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
 {
     const char *perm = "find";
-    return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
+    return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
 }
 
 struct svcinfo
@@ -175,7 +179,7 @@
 };
 
 
-uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
+uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
 {
     struct svcinfo *si = find_svc(s, len);
 
@@ -192,7 +196,7 @@
         }
     }
 
-    if (!svc_can_find(s, len, spid, uid)) {
+    if (!svc_can_find(s, len, spid, sid, uid)) {
         return 0;
     }
 
@@ -200,7 +204,7 @@
 }
 
 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) {
+                   uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) {
     struct svcinfo *si;
 
     //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -209,7 +213,7 @@
     if (!handle || (len == 0) || (len > 127))
         return -1;
 
-    if (!svc_can_register(s, len, spid, uid)) {
+    if (!svc_can_register(s, len, spid, sid, uid)) {
         ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
              str8(s, len), handle, uid);
         return -1;
@@ -248,7 +252,7 @@
 }
 
 int svcmgr_handler(struct binder_state *bs,
-                   struct binder_transaction_data *txn,
+                   struct binder_transaction_data_secctx *txn_secctx,
                    struct binder_io *msg,
                    struct binder_io *reply)
 {
@@ -260,6 +264,8 @@
     int allow_isolated;
     uint32_t dumpsys_priority;
 
+    struct binder_transaction_data *txn = &txn_secctx->transaction_data;
+
     //ALOGI("target=%p code=%d pid=%d uid=%d\n",
     //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
 
@@ -274,6 +280,7 @@
     // Note that we ignore the strict_policy and don't propagate it
     // further (since we do no outbound RPCs anyway).
     strict_policy = bio_get_uint32(msg);
+    bio_get_uint32(msg);  // Ignore worksource header.
     s = bio_get_string16(msg, &len);
     if (s == NULL) {
         return -1;
@@ -304,7 +311,8 @@
         if (s == NULL) {
             return -1;
         }
-        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
+        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
+                                 (const char*) txn_secctx->secctx);
         if (!handle)
             break;
         bio_put_ref(reply, handle);
@@ -319,7 +327,7 @@
         allow_isolated = bio_get_uint32(msg) ? 1 : 0;
         dumpsys_priority = bio_get_uint32(msg);
         if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
-                           txn->sender_pid))
+                           txn->sender_pid, (const char*) txn_secctx->secctx))
             return -1;
         break;
 
@@ -327,7 +335,7 @@
         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)) {
+        if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) {
             ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                     txn->sender_euid);
             return -1;
@@ -403,7 +411,11 @@
 
     cb.func_audit = audit_callback;
     selinux_set_callback(SELINUX_CB_AUDIT, cb);
+#ifdef VENDORSERVICEMANAGER
+    cb.func_log = selinux_vendor_log_callback;
+#else
     cb.func_log = selinux_log_callback;
+#endif
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
 #ifdef VENDORSERVICEMANAGER
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 4d93cb4..152ac28 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -13,5 +13,6 @@
     onrestart restart cameraserver
     onrestart restart keystore
     onrestart restart gatekeeperd
+    onrestart restart thermalservice
     writepid /dev/cpuset/system-background/tasks
     shutdown critical
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
new file mode 100644
index 0000000..cc4c842
--- /dev/null
+++ b/cmds/surfacereplayer/OWNERS
@@ -0,0 +1,2 @@
+mathias@google.com
+racarr@google.com
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 0bc08a9..c70bc3e 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -30,14 +30,13 @@
 
 message SurfaceChange {
     required int32 id = 1;
-
+    reserved 7;
     oneof SurfaceChange {
         PositionChange              position                = 2;
         SizeChange                  size                    = 3;
         AlphaChange                 alpha                   = 4;
         LayerChange                 layer                   = 5;
         CropChange                  crop                    = 6;
-        FinalCropChange             final_crop              = 7;
         MatrixChange                matrix                  = 8;
         OverrideScalingModeChange   override_scaling_mode   = 9;
         TransparentRegionHintChange transparent_region_hint = 10;
@@ -46,6 +45,7 @@
         OpaqueFlagChange            opaque_flag             = 13;
         SecureFlagChange            secure_flag             = 14;
         DeferredTransactionChange   deferred_transaction    = 15;
+        CornerRadiusChange          corner_radius           = 16;
     }
 }
 
@@ -63,6 +63,10 @@
     required float alpha = 1;
 }
 
+message CornerRadiusChange {
+    required float corner_radius = 1;
+}
+
 message LayerChange {
     required uint32 layer = 1;
 }
@@ -71,10 +75,6 @@
     required Rectangle rectangle = 1;
 }
 
-message FinalCropChange {
-    required Rectangle rectangle = 1;
-}
-
 message MatrixChange {
     required float dsdx = 1;
     required float dtdx = 2;
@@ -165,7 +165,7 @@
 message DisplayCreation {
     required int32     id                = 1;
     required string    name              = 2;
-    required int32     type              = 3;
+    optional uint64    display_id        = 3;
     required bool      is_secure         = 4;
 }
 
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
index 5caceec..7632311 100644
--- a/cmds/surfacereplayer/replayer/Android.bp
+++ b/cmds/surfacereplayer/replayer/Android.bp
@@ -1,6 +1,5 @@
 cc_library_shared {
     name: "libsurfacereplayer",
-    clang: true,
     srcs: [
         "BufferQueueScheduler.cpp",
         "Event.cpp",
@@ -16,7 +15,6 @@
 	"-Wno-float-equal",
 	"-Wno-sign-conversion",
 	"-Wno-padded",
-	"-std=c++14",
     ],
     static_libs: [
         "libtrace_proto",
@@ -41,7 +39,6 @@
 
 cc_binary {
     name: "surfacereplayer",
-    clang: true,
     srcs: [
         "Main.cpp",
     ],
@@ -61,6 +58,5 @@
 	"-Wno-float-conversion",
 	"-Wno-disabled-macro-expansion",
 	"-Wno-float-equal",
-	"-std=c++14",
     ],
 }
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
index 7090bdb..fbfcacf 100644
--- a/cmds/surfacereplayer/replayer/Main.cpp
+++ b/cmds/surfacereplayer/replayer/Main.cpp
@@ -94,7 +94,7 @@
     }
 
     char** input = argv + optind;
-    if (input[0] == NULL) {
+    if (input[0] == nullptr) {
         std::cerr << "No trace file provided...exiting" << std::endl;
         abort();
     }
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 4140f40..34886a9 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -286,10 +286,6 @@
             std::thread(&Replayer::createSurfaceControl, this, increment.surface_creation(), event)
                     .detach();
         } break;
-        case increment.kSurfaceDeletion: {
-            std::thread(&Replayer::deleteSurfaceControl, this, increment.surface_deletion(), event)
-                    .detach();
-        } break;
         case increment.kBufferUpdate: {
             std::lock_guard<std::mutex> lock1(mLayerLock);
             std::lock_guard<std::mutex> lock2(mBufferQueueSchedulerLock);
@@ -385,12 +381,12 @@
             case SurfaceChange::SurfaceChangeCase::kCrop:
                 setCrop(transaction, change.id(), change.crop());
                 break;
+            case SurfaceChange::SurfaceChangeCase::kCornerRadius:
+                setCornerRadius(transaction, change.id(), change.corner_radius());
+                break;
             case SurfaceChange::SurfaceChangeCase::kMatrix:
                 setMatrix(transaction, change.id(), change.matrix());
                 break;
-            case SurfaceChange::SurfaceChangeCase::kFinalCrop:
-                setFinalCrop(transaction, change.id(), change.final_crop());
-                break;
             case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
                 setOverrideScalingMode(transaction, change.id(),
                         change.override_scaling_mode());
@@ -489,17 +485,14 @@
 
     Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
             cc.rectangle().bottom());
-    t.setCrop(mLayers[id], r);
+    t.setCrop_legacy(mLayers[id], r);
 }
 
-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());
-    t.setFinalCrop(mLayers[id], r);
+void Replayer::setCornerRadius(SurfaceComposerClient::Transaction& t,
+        layer_id id, const CornerRadiusChange& cc) {
+    ALOGV("Layer %d: Setting Corner Radius -- cornerRadius=%d", id, cc.corner_radius());
+
+    t.setCornerRadius(mLayers[id], cc.corner_radius());
 }
 
 void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
@@ -570,7 +563,7 @@
 
     auto handle = mLayers[dtc.layer_id()]->getHandle();
 
-    t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number());
+    t.deferTransactionUntil_legacy(mLayers[id], handle, dtc.frame_number());
 }
 
 void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
@@ -631,47 +624,10 @@
     return NO_ERROR;
 }
 
-status_t Replayer::deleteSurfaceControl(
-        const SurfaceDeletion& delete_, const std::shared_ptr<Event>& event) {
-    ALOGV("Deleting %d Surface Control", delete_.id());
-    event->readyToExecute();
-
-    std::lock_guard<std::mutex> lock1(mPendingLayersLock);
-
-    mLayersPendingRemoval.push_back(delete_.id());
-
-    const auto& iterator = mBufferQueueSchedulers.find(delete_.id());
-    if (iterator != mBufferQueueSchedulers.end()) {
-        (*iterator).second->stopScheduling();
-    }
-
-    std::lock_guard<std::mutex> lock2(mLayerLock);
-    if (mLayers[delete_.id()] != nullptr) {
-        mComposerClient->destroySurface(mLayers[delete_.id()]->getHandle());
-    }
-
-    return NO_ERROR;
-}
-
-void Replayer::doDeleteSurfaceControls() {
-    std::lock_guard<std::mutex> lock1(mPendingLayersLock);
-    std::lock_guard<std::mutex> lock2(mLayerLock);
-    if (!mLayersPendingRemoval.empty()) {
-        for (int id : mLayersPendingRemoval) {
-            mLayers.erase(id);
-            mColors.erase(id);
-            mBufferQueueSchedulers.erase(id);
-        }
-        mLayersPendingRemoval.clear();
-    }
-}
-
 status_t Replayer::injectVSyncEvent(
         const VSyncEvent& vSyncEvent, const std::shared_ptr<Event>& event) {
     ALOGV("Injecting VSync Event");
 
-    doDeleteSurfaceControls();
-
     event->readyToExecute();
 
     SurfaceComposerClient::injectVSync(vSyncEvent.when());
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 295403e..ad807ee 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -70,8 +70,6 @@
     status_t doTransaction(const Transaction& transaction, const std::shared_ptr<Event>& event);
     status_t createSurfaceControl(const SurfaceCreation& create,
             const std::shared_ptr<Event>& event);
-    status_t deleteSurfaceControl(const SurfaceDeletion& delete_,
-            const std::shared_ptr<Event>& event);
     status_t injectVSyncEvent(const VSyncEvent& vsyncEvent, const std::shared_ptr<Event>& event);
     void createDisplay(const DisplayCreation& create, const std::shared_ptr<Event>& event);
     void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event);
@@ -92,8 +90,8 @@
             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 setCornerRadius(SurfaceComposerClient::Transaction& t,
+            layer_id id, const CornerRadiusChange& cc);
     void setMatrix(SurfaceComposerClient::Transaction& t,
             layer_id id, const MatrixChange& mc);
     void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
@@ -120,7 +118,6 @@
     void setDisplayProjection(SurfaceComposerClient::Transaction& t,
             display_id id, const ProjectionChange& pc);
 
-    void doDeleteSurfaceControls();
     void waitUntilTimestamp(int64_t timestamp);
     void waitUntilDeferredTransactionLayerExists(
             const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock);
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index a892e46..d63d97f 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -172,7 +172,7 @@
 def display_create(increment):
     increment.display_creation.id = int(input("Enter id: "))
     increment.display_creation.name = str(raw_input("Enter name: "))
-    increment.display_creation.type = int(input("Enter type: "))
+    increment.display_creation.display_id = int(input("Enter display ID: "))
     increment.display_creation.is_secure = bool(input("Enter if secure: "))
 
 def display_delete(increment):
diff --git a/data/etc/android.hardware.biometrics.face.xml b/data/etc/android.hardware.biometrics.face.xml
new file mode 100644
index 0000000..7fa0bf9
--- /dev/null
+++ b/data/etc/android.hardware.biometrics.face.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard set of features for a biometric face authentication sensor. -->
+<permissions>
+    <feature name="android.hardware.biometrics.face" />
+</permissions>
diff --git a/data/etc/android.hardware.nfc.ese.xml b/data/etc/android.hardware.nfc.ese.xml
new file mode 100644
index 0000000..6642bb2
--- /dev/null
+++ b/data/etc/android.hardware.nfc.ese.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports eSE-based NFC card
+     emulation -->
+<permissions>
+    <feature name="android.hardware.nfc.ese" />
+</permissions>
diff --git a/data/etc/android.hardware.nfc.uicc.xml b/data/etc/android.hardware.nfc.uicc.xml
new file mode 100644
index 0000000..4f12de4
--- /dev/null
+++ b/data/etc/android.hardware.nfc.uicc.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports uicc-based NFC card
+     emulation -->
+<permissions>
+    <feature name="android.hardware.nfc.uicc" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.ims.xml b/data/etc/android.hardware.telephony.ims.xml
new file mode 100644
index 0000000..eeb7b00
--- /dev/null
+++ b/data/etc/android.hardware.telephony.ims.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices that support IMS via ImsService APIs. -->
+<permissions>
+    <feature name="android.hardware.telephony.ims" />
+</permissions>
diff --git a/data/etc/android.hardware.usb.accessory.xml b/data/etc/android.hardware.usb.accessory.xml
index 80a0904..29df966 100644
--- a/data/etc/android.hardware.usb.accessory.xml
+++ b/data/etc/android.hardware.usb.accessory.xml
@@ -17,6 +17,4 @@
 <!-- This is the standard feature indicating that the device supports USB accessories. -->
 <permissions>
     <feature name="android.hardware.usb.accessory" />
-    <library name="com.android.future.usb.accessory"
-            file="/system/framework/com.android.future.usb.accessory.jar" />
 </permissions>
diff --git a/data/etc/android.software.ipsec_tunnels.xml b/data/etc/android.software.ipsec_tunnels.xml
new file mode 100644
index 0000000..f7ffc02
--- /dev/null
+++ b/data/etc/android.software.ipsec_tunnels.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+     This is the feature indicating that the device has support for multinetworking-capable IPsec
+     tunnels
+-->
+
+<permissions>
+    <feature name="android.software.ipsec_tunnels" />
+</permissions>
diff --git a/data/etc/android.software.secure_lock_screen.xml b/data/etc/android.software.secure_lock_screen.xml
new file mode 100644
index 0000000..3464487
--- /dev/null
+++ b/data/etc/android.software.secure_lock_screen.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<permissions>
+    <feature name="android.software.secure_lock_screen" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 561f5ba..ad7791e 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -36,18 +36,15 @@
     <feature name="android.hardware.type.automotive" />
 
     <!-- basic system services -->
-    <feature name="android.software.app_widgets" />
     <feature name="android.software.connectionservice" />
     <feature name="android.software.voice_recognizers" notLowRam="true" />
     <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.print" />
-
-    <!-- Feature to specify if the device supports adding device admins. -->
-    <feature name="android.software.device_admin" />
-
-    <!-- Feature to specify if the device support managed users. -->
-    <feature name="android.software.managed_users" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- devices with GPS must include android.hardware.location.gps.xml -->
     <!-- devices with an autofocus camera and/or flash must include either
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index 8b5a461..915e579 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -43,6 +43,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 060a334..619d017 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -51,6 +51,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 6db2627..52524ca 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -51,6 +51,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index e2ab71a..0f364c1 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -35,6 +35,7 @@
 
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- input management and third-party input method editors -->
     <feature name="android.software.input_methods" />
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
deleted file mode 100644
index b32c92e..0000000
--- a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IARC_VIDEO_BRIDGE_H
-#define ANDROID_IARC_VIDEO_BRIDGE_H
-
-#include <arc/IArcBridgeService.h>
-#include <binder/IInterface.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class IArcVideoBridge : public IInterface {
-public:
-    DECLARE_META_INTERFACE(ArcVideoBridge);
-
-    // Returns MojoBootstrapResult for creating mojo ipc channel of
-    // VideoAcceleratorFactory.
-    virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() = 0;
-
-    // Get the version of the remote VideoHost on Chromium side.
-    virtual int32_t hostVersion() = 0;
-};
-
-class BnArcVideoBridge : public BnInterface<IArcVideoBridge> {
-public:
-    virtual status_t onTransact(
-            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
-};
-
-};  // namespace android
-
-#endif // ANDROID_IARC_VIDEO_BRIDGE_H
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index 4de314d..c87ee56 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -48,6 +48,14 @@
         uint8_t *data,
         size_t size);
 
+typedef void (*CasPluginCallbackExt)(
+        void *appData,
+        int32_t event,
+        int32_t arg,
+        uint8_t *data,
+        size_t size,
+        const CasSessionId *sessionId);
+
 struct CasFactory {
     CasFactory() {}
     virtual ~CasFactory() {}
@@ -67,6 +75,13 @@
             CasPluginCallback callback,
             CasPlugin **plugin) = 0;
 
+    // Construct a new extend instance of a CasPlugin given a CA_system_id
+    virtual status_t createPlugin(
+            int32_t CA_system_id,
+            void *appData,
+            CasPluginCallbackExt callback,
+            CasPlugin **plugin) = 0;
+
 private:
     CasFactory(const CasFactory &);
     CasFactory &operator=(const CasFactory &); /* NOLINT */
@@ -110,7 +125,15 @@
             int32_t arg,
             const CasData &eventData) = 0;
 
-    // Native implementation of the MediaCas Java API provision method.
+    // Deliver an session event to the CasPlugin. The format of the event is
+    // specific to the CA scheme and is opaque to the framework.
+    virtual status_t sendSessionEvent(
+            const CasSessionId &sessionId,
+            int32_t event,
+            int32_t arg,
+            const CasData &eventData) = 0;
+
+   // Native implementation of the MediaCas Java API provision method.
     virtual status_t provision(
             const String8 &provisionString) = 0;
 
diff --git a/headers/media_plugin/media/cas/DescramblerAPI.h b/headers/media_plugin/media/cas/DescramblerAPI.h
index 033c8ce..c57f606 100644
--- a/headers/media_plugin/media/cas/DescramblerAPI.h
+++ b/headers/media_plugin/media/cas/DescramblerAPI.h
@@ -72,12 +72,12 @@
     // associated MediaCas session is used to load decryption keys
     // into the crypto/cas plugin.  The keys are then referenced by key-id
     // in the 'key' parameter to the decrypt() method.
-    // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if
+    // Should return NO_ERROR on success, ERROR_CAS_SESSION_NOT_OPENED if
     // the session is not opened and a code from MediaErrors.h otherwise.
     virtual status_t setMediaCasSession(const CasSessionId& sessionId) = 0;
 
     // If the error returned falls into the range
-    // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be
+    // ERROR_CAS_VENDOR_MIN..ERROR_CAS_VENDOR_MAX, errorDetailMsg should be
     // filled in with an appropriate string.
     // At the java level these special errors will then trigger a
     // MediaCodec.CryptoException that gives clients access to both
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index c44a1f6..17b9993 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -84,6 +84,7 @@
             kDrmPluginEventSessionReclaimed,
             kDrmPluginEventExpirationUpdate,
             kDrmPluginEventKeysChange,
+            kDrmPluginEventSessionLostState,
         };
 
         // Drm keys can be for offline content or for online streaming.
@@ -114,7 +115,8 @@
             kKeyStatusType_Expired,
             kKeyStatusType_OutputNotAllowed,
             kKeyStatusType_StatusPending,
-            kKeyStatusType_InternalError
+            kKeyStatusType_InternalError,
+            kKeyStatusType_UsableInFuture
         };
 
         // Used by sendKeysChange to report the usability status of each
@@ -139,6 +141,8 @@
             kHdcpV2_1,
             // HDCP version 2.2 Type 1.
             kHdcpV2_2,
+            // HDCP version 2.3 Type 1.
+            kHdcpV2_3,
             // No digital output, implicitly secure
             kHdcpNoOutput = 0x7fff
         };
@@ -167,6 +171,25 @@
             kSecurityLevelHwSecureAll
         };
 
+        // An offline license may be usable or inactive. The keys in a
+        // usable offline license are available for decryption. When
+        // the offline license state is inactive, the keys have been
+        // marked for release using getKeyRequest with
+        // kKeyType_Release but the key response has not been
+        // received. The keys in an inactive offline license are not
+        // usable for decryption.
+
+        enum OfflineLicenseState {
+            // The offline license state is unknown due to an error
+            kOfflineLicenseStateUnknown,
+            // Offline license state is usable, the keys may be used for decryption.
+            kOfflineLicenseStateUsable,
+            // Offline license state is released, the keys have been marked for
+            // release using getKeyRequest() with kKeyType_Release but the
+            // key response has not been received.
+            kOfflineLicenseStateReleased
+        };
+
         DrmPlugin() {}
         virtual ~DrmPlugin() {}
 
diff --git a/headers/media_plugin/media/hardware/HardwareAPI.h b/headers/media_plugin/media/hardware/HardwareAPI.h
index 6c1ba3d..ae0220a 100644
--- a/headers/media_plugin/media/hardware/HardwareAPI.h
+++ b/headers/media_plugin/media/hardware/HardwareAPI.h
@@ -425,7 +425,7 @@
 
 // HDR color description parameters.
 // This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the
-// 'OMX.google.android.index.describeHDRColorInfo' extension is given and an HDR stream
+// 'OMX.google.android.index.describeHDRStaticInfo' extension is given and an HDR stream
 // is detected.  Component SHALL behave as described below if it supports this extension.
 //
 // Currently, only Static Metadata Descriptor Type 1 support is required.
@@ -496,6 +496,64 @@
     HDRStaticInfo sInfo;           // IN/OUT
 };
 
+// HDR10+ metadata configuration.
+//
+// nParamSize: size of the storage starting at nValue (must be at least 1 and at most
+//             MAX_HDR10PLUSINFO_SIZE). This field must not be modified by the component.
+// nParamSizeUsed: size of the actual HDR10+ metadata starting at nValue. For OMX_SetConfig,
+//                 it must not be modified by the component. For OMX_GetConfig, the component
+//                 should put the actual size of the retrieved config in this field (and in
+//                 case where nParamSize is smaller than nParamSizeUsed, the component should
+//                 still update nParamSizeUsed without actually copying the metadata to nValue).
+// nValue: storage of the HDR10+ metadata conforming to the user_data_registered_itu_t_t35()
+//         syntax of SEI message for ST 2094-40.
+//
+// This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the
+// 'OMX.google.android.index.describeHDR10PlusInfo' extension is given. In general, this config
+// is associated with a particular frame. A typical sequence of usage is as follows:
+//
+// a) OMX_SetConfig associates the config with the next input buffer sent in OMX_EmptyThisBuffer
+//    (input A);
+// b) The component sends OMX_EventConfigUpdate to notify the client that there is a config
+//    update  on the output port that is associated with the next output buffer that's about to
+//    be sent via FillBufferDone callback (output A);
+// c) The client, upon receiving the OMX_EventConfigUpdate, calls OMX_GetConfig to retrieve
+//    the config and associates it with output A.
+//
+// All config updates will be retrieved in the order reported, and the client is required to
+// call OMX_GetConfig for each OMX_EventConfigUpdate for this config. Note that the order of
+// OMX_EventConfigUpdate relative to FillBufferDone callback determines which output frame
+// the config should be associated with, the actual OMX_GetConfig for the config could happen
+// before or after the component calls the FillBufferDone callback.
+//
+// Depending on the video codec type (in particular, whether the codec uses in-band or out-of-
+// band HDR10+ metadata), the component shall behave as detailed below:
+//
+// VIDEO DECODERS:
+// 1) If the codec utilizes out-of-band HDR10+ metadata, the decoder must support the sequence
+//    a) ~ c) outlined above;
+// 2) If the codec utilizes in-band HDR10+ metadata, OMX_SetConfig for this config should be
+//    ignored (as the metadata is embedded in the input buffer), while the notification and
+//    retrieval of the config on the output as outlined in b) & c) must be supported.
+//
+// VIDEO ENCODERS:
+// 1) If the codec utilizes out-of-band HDR10+ metadata, the decoder must support the sequence
+//    a) ~ c) outlined above;
+// 2) If the codec utilizes in-band HDR10+ metadata, OMX_SetConfig for this config outlined in
+//    a) must be supported. The notification as outlined in b) must not be sent, and the
+//    retrieval of the config via OMX_GetConfig should be ignored (as the metadata is embedded
+//    in the output buffer).
+
+#define MAX_HDR10PLUSINFO_SIZE 1024
+struct DescribeHDR10PlusInfoParams {
+    OMX_U32 nSize;                 // IN
+    OMX_VERSIONTYPE nVersion;      // IN
+    OMX_U32 nPortIndex;            // IN
+    OMX_U32 nParamSize;            // IN
+    OMX_U32 nParamSizeUsed;        // IN/OUT
+    OMX_U8 nValue[1];              // IN/OUT
+};
+
 }  // namespace android
 
 extern android::OMXPluginBase *createOMXPlugin();
diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
index dc25ded..ce30b41 100644
--- a/headers/media_plugin/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -188,7 +188,9 @@
 inline static const char *asString(OMX_AUDIO_CODINGEXTTYPE i, const char *def = "??") {
     switch (i) {
         case OMX_AUDIO_CodingAndroidAC3:  return "AndroidAC3";
+        case OMX_AUDIO_CodingAndroidEAC3: return "AndroidEAC3";
         case OMX_AUDIO_CodingAndroidOPUS: return "AndroidOPUS";
+        case OMX_AUDIO_CodingAndroidAC4:  return "AndroidAC4";
         default:                          return asString((OMX_AUDIO_CODINGTYPE)i, def);
     }
 }
@@ -533,9 +535,11 @@
 //      case OMX_IndexConfigCommit:                     return "ConfigCommit";
         case OMX_IndexConfigAndroidVendorExtension:     return "ConfigAndroidVendorExtension";
         case OMX_IndexParamAudioAndroidAc3:             return "ParamAudioAndroidAc3";
+        case OMX_IndexConfigAudioPresentation:          return "ConfigAudioPresentation";
         case OMX_IndexParamAudioAndroidOpus:            return "ParamAudioAndroidOpus";
         case OMX_IndexParamAudioAndroidAacPresentation: return "ParamAudioAndroidAacPresentation";
         case OMX_IndexParamAudioAndroidEac3:            return "ParamAudioAndroidEac3";
+        case OMX_IndexParamAudioAndroidAc4:             return "ParamAudioAndroidAc4";
         case OMX_IndexParamAudioProfileQuerySupported:  return "ParamAudioProfileQuerySupported";
 //      case OMX_IndexParamNalStreamFormatSupported:    return "ParamNalStreamFormatSupported";
 //      case OMX_IndexParamNalStreamFormat:             return "ParamNalStreamFormat";
@@ -907,6 +911,9 @@
         case OMX_VIDEO_AVCLevel5:  return "Level5";
         case OMX_VIDEO_AVCLevel51: return "Level51";
         case OMX_VIDEO_AVCLevel52: return "Level52";
+        case OMX_VIDEO_AVCLevel6:  return "Level6";
+        case OMX_VIDEO_AVCLevel61: return "Level61";
+        case OMX_VIDEO_AVCLevel62: return "Level62";
         default:                   return def;
     }
 }
diff --git a/headers/media_plugin/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
index 8409553..477faed 100644
--- a/headers/media_plugin/media/openmax/OMX_AudioExt.h
+++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h
@@ -48,6 +48,7 @@
     OMX_AUDIO_CodingAndroidAC3,         /**< AC3 encoded data */
     OMX_AUDIO_CodingAndroidOPUS,        /**< OPUS encoded data */
     OMX_AUDIO_CodingAndroidEAC3,        /**< EAC3 encoded data */
+    OMX_AUDIO_CodingAndroidAC4,         /**< AC4 encoded data */
 } OMX_AUDIO_CODINGEXTTYPE;
 
 typedef struct OMX_AUDIO_PARAM_ANDROID_AC3TYPE {
@@ -68,6 +69,15 @@
                                         variable or unknown sampling rate. */
 } OMX_AUDIO_PARAM_ANDROID_EAC3TYPE;
 
+typedef struct OMX_AUDIO_PARAM_ANDROID_AC4TYPE {
+    OMX_U32 nSize;                 /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< port that this structure applies to */
+    OMX_U32 nChannels;             /**< Number of channels */
+    OMX_U32 nSampleRate;           /**< Sampling rate of the source data.  Use 0 for
+                                        variable or unknown sampling rate. */
+} OMX_AUDIO_PARAM_ANDROID_AC4TYPE;
+
 typedef struct OMX_AUDIO_PARAM_ANDROID_OPUSTYPE {
     OMX_U32 nSize;            /**< size of the structure in bytes */
     OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
@@ -117,6 +127,13 @@
    OMX_U32 nProfileIndex; /**< Used to query for individual profile support information */
 } OMX_AUDIO_PARAM_ANDROID_PROFILETYPE;
 
+typedef struct OMX_AUDIO_CONFIG_ANDROID_AUDIOPRESENTATION {
+    OMX_U32 nSize;                 /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_S32 nPresentationId;       /**< presentation id */
+    OMX_S32 nProgramId;            /**< program id */
+} OMX_AUDIO_CONFIG_ANDROID_AUDIOPRESENTATION;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/headers/media_plugin/media/openmax/OMX_Core.h b/headers/media_plugin/media/openmax/OMX_Core.h
index bb974b3..9ff934e 100644
--- a/headers/media_plugin/media/openmax/OMX_Core.h
+++ b/headers/media_plugin/media/openmax/OMX_Core.h
@@ -542,6 +542,20 @@
      *  fool-proof way to do that for video encoders.
      */
     OMX_EventDataSpaceChanged,
+
+    /**
+     * Event when a component has an updated configuration on output for the client to retrieve.
+     * |arg1| contains the port index (currently only output port is valid). |arg2| contains the
+     * index of the updated config.
+     *
+     * For config updates that's associated with one frame, the update should be applied to the
+     * next output frame that comes in EmptyBufferDone callback.
+     *
+     * Upon receiving this event, the client must call the corresponding OMX_GetConfig to retrieve
+     * the config update.
+     */
+    OMX_EventConfigUpdate,
+
     OMX_EventMax = 0x7FFFFFFF
 } OMX_EVENTTYPE;
 
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index 716d959..479e9b8 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -64,6 +64,8 @@
     OMX_IndexParamAudioAndroidEac3,                 /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */
     OMX_IndexParamAudioProfileQuerySupported,       /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */
     OMX_IndexParamAudioAndroidAacDrcPresentation,   /**< reference: OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */
+    OMX_IndexParamAudioAndroidAc4,                  /**< reference: OMX_AUDIO_PARAM_ANDROID_AC4TYPE */
+    OMX_IndexConfigAudioPresentation,               /**< reference: OMX_AUDIO_CONFIG_ANDROID_AUDIOPRESENTATION */
     OMX_IndexExtAudioEndUnused,
 
     /* Image parameters and configurations */
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index 9fd2fd2..b6edaa9 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -832,6 +832,9 @@
     OMX_VIDEO_AVCLevel5   = 0x4000,   /**< Level 5 */
     OMX_VIDEO_AVCLevel51  = 0x8000,   /**< Level 5.1 */
     OMX_VIDEO_AVCLevel52  = 0x10000,  /**< Level 5.2 */
+    OMX_VIDEO_AVCLevel6   = 0x20000,  /**< Level 6 */
+    OMX_VIDEO_AVCLevel61  = 0x40000,  /**< Level 6.1 */
+    OMX_VIDEO_AVCLevel62  = 0x80000,  /**< Level 6.2 */
     OMX_VIDEO_AVCLevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_VIDEO_AVCLevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
     OMX_VIDEO_AVCLevelMax = 0x7FFFFFFF
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index bbf157b..435fcc8 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -164,6 +164,8 @@
     // HDR profiles also support passing HDR metadata
     OMX_VIDEO_VP9Profile2HDR = 0x1000,
     OMX_VIDEO_VP9Profile3HDR = 0x2000,
+    OMX_VIDEO_VP9Profile2HDR10Plus = 0x4000,
+    OMX_VIDEO_VP9Profile3HDR10Plus = 0x8000,
     OMX_VIDEO_VP9ProfileUnknown = 0x6EFFFFFF,
     OMX_VIDEO_VP9ProfileMax = 0x7FFFFFFF
 } OMX_VIDEO_VP9PROFILETYPE;
@@ -216,6 +218,7 @@
     OMX_VIDEO_HEVCProfileMainStill    = 0x4,
     // Main10 profile with HDR SEI support.
     OMX_VIDEO_HEVCProfileMain10HDR10  = 0x1000,
+    OMX_VIDEO_HEVCProfileMain10HDR10Plus  = 0x2000,
     OMX_VIDEO_HEVCProfileMax          = 0x7FFFFFFF
 } OMX_VIDEO_HEVCPROFILETYPE;
 
diff --git a/include/OWNERS b/include/OWNERS
new file mode 100644
index 0000000..db52850
--- /dev/null
+++ b/include/OWNERS
@@ -0,0 +1,16 @@
+alexeykuzmin@google.com
+dangittik@google.com
+jreck@google.com
+lajos@google.com
+mathias@google.com
+michaelwr@google.com
+nona@google.com
+racarr@google.com
+romainguy@android.com
+santoscordon@google.com
+stoza@google.com
+svv@google.com
+
+# For multinetwork.h only.
+lorenzo@google.com
+
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 43346fe..44883cc 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -26,12 +26,11 @@
 #ifndef ANDROID_CHOREOGRAPHER_H
 #define ANDROID_CHOREOGRAPHER_H
 
+#include <stdint.h>
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 24
-
 struct AChoreographer;
 typedef struct AChoreographer AChoreographer;
 
@@ -46,26 +45,56 @@
 typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data);
 
 /**
+ * Prototype of the function that is called when a new frame is being rendered.
+ * It's passed the time that the frame is being rendered as nanoseconds in the
+ * CLOCK_MONOTONIC time base, as well as the data pointer provided by the
+ * application that registered a callback. All callbacks that run as part of
+ * rendering a frame will observe the same frame time, so it should be used
+ * whenever events need to be synchronized (e.g. animations).
+ */
+typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
+
+#if __ANDROID_API__ >= 24
+
+/**
  * Get the AChoreographer instance for the current thread. This must be called
  * on an ALooper thread.
  */
-AChoreographer* AChoreographer_getInstance();
+AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24);
 
 /**
- * Post a callback to be run on the next frame. The data pointer provided will
- * be passed to the callback function when it's called.
+ * Deprecated: Use AChoreographer_postFrameCallback64 instead.
  */
 void AChoreographer_postFrameCallback(AChoreographer* choreographer,
-                AChoreographer_frameCallback callback, void* data);
+        AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+
 /**
- * Post a callback to be run on the frame following the specified delay. The
+ * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead.
+ */
+void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
+                AChoreographer_frameCallback callback, void* data,
+                long delayMillis) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+
+#endif /* __ANDROID_API__ >= 24 */
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * Power a callback to be run on the next frame.  The data pointer provided will
+ * be passed to the callback function when it's called.
+ */
+void AChoreographer_postFrameCallback64(AChoreographer* chroreographer,
+                AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
+
+/**
+ * Post a callback to be run on the frame following the specified delay.  The
  * data pointer provided will be passed to the callback function when it's
  * called.
  */
-void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
-                AChoreographer_frameCallback callback, void* data, long delayMillis);
+void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
+                AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29);
 
-#endif /* __ANDROID_API__ >= 24 */
+#endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
 
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 6287332..ef6c5a2 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -30,6 +30,10 @@
 
 #include <android/asset_manager.h>
 
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -676,34 +680,34 @@
  * Return the current configuration screen width in dp units, or
  * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenWidthDp(AConfiguration* config);
+int32_t AConfiguration_getScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value);
+void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
 
 /**
  * Return the current configuration screen height in dp units, or
  * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenHeightDp(AConfiguration* config);
+int32_t AConfiguration_getScreenHeightDp(AConfiguration* config) __INTRODUCED_IN(13);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value);
+void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
 
 /**
  * Return the configuration's smallest screen width in dp units, or
  * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config);
+int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
 
 /**
  * Set the configuration's smallest screen width in dp units.
  */
-void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
+void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
 #endif /* __ANDROID_API__ >= 13 */
 
 #if __ANDROID_API__ >= 17
@@ -711,12 +715,12 @@
  * Return the configuration's layout direction, or
  * ACONFIGURATION_LAYOUTDIR_ANY if not set.
  */
-int32_t AConfiguration_getLayoutDirection(AConfiguration* config);
+int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_IN(17);
 
 /**
  * Set the configuration's layout direction.
  */
-void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value);
+void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17);
 #endif /* __ANDROID_API__ >= 17 */
 
 /**
diff --git a/include/android/font.h b/include/android/font.h
new file mode 100644
index 0000000..435a573
--- /dev/null
+++ b/include/android/font.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup Font
+ * {
+ */
+
+/**
+ * @file font.h
+ * @brief Provides some constants used in system_fonts.h or fonts_matcher.h
+ *
+ * Available since API level 29.
+ */
+
+#ifndef ANDROID_FONT_H
+#define ANDROID_FONT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+enum {
+    /** The minimum value fot the font weight value. */
+    AFONT_WEIGHT_MIN = 0,
+
+    /** A font weight value for the thin weight. */
+    AFONT_WEIGHT_THIN = 100,
+
+    /** A font weight value for the extra-light weight. */
+    AFONT_WEIGHT_EXTRA_LIGHT = 200,
+
+    /** A font weight value for the light weight. */
+    AFONT_WEIGHT_LIGHT = 300,
+
+    /** A font weight value for the normal weight. */
+    AFONT_WEIGHT_NORMAL = 400,
+
+    /** A font weight value for the medium weight. */
+    AFONT_WEIGHT_MEDIUM = 500,
+
+    /** A font weight value for the semi-bold weight. */
+    AFONT_WEIGHT_SEMI_BOLD = 600,
+
+    /** A font weight value for the bold weight. */
+    AFONT_WEIGHT_BOLD = 700,
+
+    /** A font weight value for the extra-bold weight. */
+    AFONT_WEIGHT_EXTRA_BOLD = 800,
+
+    /** A font weight value for the black weight. */
+    AFONT_WEIGHT_BLACK = 900,
+
+    /** The maximum value for the font weight value. */
+    AFONT_WEIGHT_MAX = 1000
+};
+
+/**
+ * AFont provides information of the single font configuration.
+ */
+struct AFont;
+
+/**
+ * Close an AFont.
+ *
+ * \param font a font returned by ASystemFontIterator_next or AFontMatchert_match.
+ *        Do nothing if NULL is passed.
+ */
+void AFont_close(AFont* _Nullable font) __INTRODUCED_IN(29);
+
+/**
+ * Return an absolute path to the current font file.
+ *
+ * Here is a list of font formats returned by this method:
+ * <ul>
+ *   <li>OpenType</li>
+ *   <li>OpenType Font Collection</li>
+ *   <li>TrueType</li>
+ *   <li>TrueType Collection</li>
+ * </ul>
+ * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc.
+ *
+ * The font file returned is guaranteed to be opend with O_RDONLY.
+ * Note that the returned pointer is valid until AFont_close() is called for the given font.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return a string of the font file path.
+ */
+const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a weight value associated with the current font.
+ *
+ * The weight values are positive and less than or equal to 1000.
+ * Here are pairs of the common names and their values.
+ * <p>
+ *  <table>
+ *  <tr>
+ *  <th align="center">Value</th>
+ *  <th align="center">Name</th>
+ *  <th align="center">NDK Definition</th>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">100</td>
+ *  <td align="center">Thin</td>
+ *  <td align="center">{@link AFONT_WEIGHT_THIN}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">200</td>
+ *  <td align="center">Extra Light (Ultra Light)</td>
+ *  <td align="center">{@link AFONT_WEIGHT_EXTRA_LIGHT}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">300</td>
+ *  <td align="center">Light</td>
+ *  <td align="center">{@link AFONT_WEIGHT_LIGHT}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">400</td>
+ *  <td align="center">Normal (Regular)</td>
+ *  <td align="center">{@link AFONT_WEIGHT_NORMAL}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">500</td>
+ *  <td align="center">Medium</td>
+ *  <td align="center">{@link AFONT_WEIGHT_MEDIUM}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">600</td>
+ *  <td align="center">Semi Bold (Demi Bold)</td>
+ *  <td align="center">{@link AFONT_WEIGHT_SEMI_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">700</td>
+ *  <td align="center">Bold</td>
+ *  <td align="center">{@link AFONT_WEIGHT_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">800</td>
+ *  <td align="center">Extra Bold (Ultra Bold)</td>
+ *  <td align="center">{@link AFONT_WEIGHT_EXTRA_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">900</td>
+ *  <td align="center">Black (Heavy)</td>
+ *  <td align="center">{@link AFONT_WEIGHT_BLACK}</td>
+ *  </tr>
+ *  </table>
+ * </p>
+ * Note that the weight value may fall in between above values, e.g. 250 weight.
+ *
+ * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
+ */
+uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return true if the current font is italic, otherwise returns false.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return true if italic, otherwise false.
+ */
+bool AFont_isItalic(const AFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a IETF BCP47 compliant language tag associated with the current font.
+ *
+ * For information about IETF BCP47, read [Locale.forLanguageTag(java.lang.String)](https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)")
+ *
+ * Note that the returned pointer is valid until AFont_close() is called.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return a IETF BCP47 compliant language tag or nullptr if not available.
+ */
+const char* _Nullable AFont_getLocale(const AFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a font collection index value associated with the current font.
+ *
+ * In case the target font file is a font collection (e.g. .ttc or .otc), this
+ * returns a non-negative value as an font offset in the collection. This
+ * always returns 0 if the target font file is a regular font.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return a font collection index.
+ */
+size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a count of font variation settings associated with the current font
+ *
+ * The font variation settings are provided as multiple tag-values pairs.
+ *
+ * For example, bold italic font may have following font variation settings:
+ *     'wght' 700, 'slnt' -12
+ * In this case, AFont_getAxisCount returns 2 and AFont_getAxisTag
+ * and AFont_getAxisValue will return following values.
+ * \code{.cpp}
+ *     AFont* font = AFontIterator_next(ite);
+ *
+ *     // Returns the number of axes
+ *     AFont_getAxisCount(font);  // Returns 2
+ *
+ *     // Returns the tag-value pair for the first axis.
+ *     AFont_getAxisTag(font, 0);  // Returns 'wght'(0x77676874)
+ *     AFont_getAxisValue(font, 0);  // Returns 700.0
+ *
+ *     // Returns the tag-value pair for the second axis.
+ *     AFont_getAxisTag(font, 1);  // Returns 'slnt'(0x736c6e74)
+ *     AFont_getAxisValue(font, 1);  // Returns -12.0
+ * \endcode
+ *
+ * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \return a number of font variation settings.
+ */
+size_t AFont_getAxisCount(const AFont* _Nonnull font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an OpenType axis tag associated with the current font.
+ *
+ * See AFont_getAxisCount for more details.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \param axisIndex an index to the font variation settings. Passing value larger than or
+ *        equal to {@link AFont_getAxisCount} is not allowed.
+ * \return an OpenType axis tag value for the given font variation setting.
+ */
+uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex)
+      __INTRODUCED_IN(29);
+
+/**
+ * Return an OpenType axis value associated with the current font.
+ *
+ * See AFont_getAxisCount for more details.
+ *
+ * \param font a font object. Passing NULL is not allowed.
+ * \param axisIndex an index to the font variation settings. Passing value larger than or
+ *         equal to {@link ASYstemFont_getAxisCount} is not allwed.
+ * \return a float value for the given font variation setting.
+ */
+float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex)
+      __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_FONT_H
+
+/** @} */
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
new file mode 100644
index 0000000..e286a4c
--- /dev/null
+++ b/include/android/font_matcher.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup Font
+ * {
+ */
+
+/**
+ * @file font_matcher.h
+ * @brief Provides the font matching logic with various inputs.
+ *
+ * You can use this class for deciding what font is to be used for drawing text.
+ *
+ * A matcher is created from text style, locales and UI compatibility. The match function for
+ * matcher object can be called multiple times until close function is called.
+ *
+ * Even if no font can render the given text, the match function will return a non-null result for
+ * drawing Tofu character.
+ *
+ * Examples:
+ * \code{.cpp}
+ *  // Simple font query for the ASCII character.
+ *  std::vector<uint16_t> text = { 'A' };
+ *  AFontMatcher* matcher = AFontMatcher_create("sans-serif");
+ *  ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a valid font file.
+ *  AFontMatcher_destroy(matcher);
+ *
+ *  // Querying font for CJK characters
+ *  std::vector<uint16_t> text = { 0x9AA8 };
+ *  AFontMatcher* matcher = AFontMatcher_create("sans-serif");
+ *  AFontMatcher_setLocales(matcher, "zh-CN,ja-JP");
+ *  ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Simplified Chinese font.
+ *  AFontMatcher_setLocales(matcher, "ja-JP,zh-CN");
+ *  ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Japanese font.
+ *  AFontMatcher_destroy(matcher);
+ *
+ *  // Querying font for text/color emoji
+ *  std::vector<uint16_t> text = { 0xD83D, 0xDC68, 0x200D, 0x2764, 0xFE0F, 0x200D, 0xD83D, 0xDC68 };
+ *  AFontMatcher* matcher = AFontMatcher_create("sans-serif");
+ *  ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ *  // runLength will be 8 and the font will points a color emoji font.
+ *  AFontMatcher_destroy(matcher);
+ *
+ *  // Mixture of multiple script of characters.
+ *  // 0x05D0 is a Hebrew character and 0x0E01 is a Thai character.
+ *  std::vector<uint16_t> text = { 0x05D0, 0x0E01 };
+ *  AFontMatcher* matcher = AFontMatcher_create("sans-serif");
+ *  ASystemFont* font = AFontMatcher_match(text.data(), text.length(), &runLength);
+ *  // runLength will be 1 and the font will points a Hebrew font.
+ *  AFontMatcher_destroy(matcher);
+ * \endcode
+ *
+ * Available since API level 29.
+ */
+
+#ifndef ANDROID_FONT_MATCHER_H
+#define ANDROID_FONT_MATCHER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+#include <android/font.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+enum {
+    /** A family variant value for the system default variant. */
+    AFAMILY_VARIANT_DEFAULT = 0,
+
+    /**
+     * A family variant value for the compact font family variant.
+     *
+     * The compact font family has Latin-based vertical metrics.
+     */
+    AFAMILY_VARIANT_COMPACT = 1,
+
+    /**
+     * A family variant value for the elegant font family variant.
+     *
+     * The elegant font family may have larger vertical metrics than Latin font.
+     */
+    AFAMILY_VARIANT_ELEGANT = 2,
+};
+
+/**
+ * AFontMatcher performs match operation on given parameters and available font files.
+ * This matcher is not a thread-safe object. Do not pass this matcher to other threads.
+ */
+struct AFontMatcher;
+
+/**
+ * Select the best font from given parameters.
+ *
+ */
+
+/**
+ * Creates a new AFontMatcher object
+ */
+AFontMatcher* _Nonnull AFontMatcher_create() __INTRODUCED_IN(29);
+
+/**
+ * Destroy the matcher object.
+ *
+ * \param matcher a matcher object. Passing NULL is not allowed.
+ */
+void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29);
+
+/**
+ * Set font style to matcher.
+ *
+ * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL}
+ * with non-italic style.
+ *
+ * \param matcher a matcher object. Passing NULL is not allowed.
+ * \param weight a font weight value. Only from 0 to 1000 value is valid
+ * \param italic true if italic, otherwise false.
+ */
+void AFontMatcher_setStyle(
+        AFontMatcher* _Nonnull matcher,
+        uint16_t weight,
+        bool italic) __INTRODUCED_IN(29);
+
+/**
+ * Set font locales to matcher.
+ *
+ * If this function is not called, the matcher performs with empty locale list.
+ *
+ * \param matcher a matcher object. Passing NULL is not allowed.
+ * \param languageTags a null character terminated comma separated IETF BCP47 compliant language
+ *                     tags.
+ */
+void AFontMatcher_setLocales(
+        AFontMatcher* _Nonnull matcher,
+        const char* _Nonnull languageTags) __INTRODUCED_IN(29);
+
+/**
+ * Set family variant to matcher.
+ *
+ * If this function is not called, the matcher performs with {@link AFAMILY_VARIANT_DEFAULT}.
+ *
+ * \param matcher a matcher object. Passing NULL is not allowed.
+ * \param familyVariant Must be one of {@link AFAMILY_VARIANT_DEFAULT},
+ *                      {@link AFAMILY_VARIANT_COMPACT} or {@link AFAMILY_VARIANT_ELEGANT} is valid.
+ */
+void AFontMatcher_setFamilyVariant(
+        AFontMatcher* _Nonnull matcher,
+        uint32_t familyVariant) __INTRODUCED_IN(29);
+
+/**
+ * Performs the matching from the generic font family for the text and select one font.
+ *
+ * For more information about generic font families, read [W3C spec](https://www.w3.org/TR/css-fonts-4/#generic-font-families)
+ *
+ * Even if no font can render the given text, this function will return a non-null result for
+ * drawing Tofu character.
+ *
+ * \param matcher a matcher object. Passing NULL is not allowed.
+ * \param familyName a null character terminated font family name
+ * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string.
+ * \param textLength a length of the given text buffer. This must not be zero.
+ * \param runLengthOut if not null, the font run length will be filled.
+ * \return a font to be used for given text and params. You need to release the returned font by
+ *         ASystemFont_close when it is no longer needed.
+ */
+AFont* _Nonnull AFontMatcher_match(
+        const AFontMatcher* _Nonnull matcher,
+        const char* _Nonnull familyName,
+        const uint16_t* _Nonnull text,
+        const uint32_t textLength,
+        uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_FONT_MATCHER_H
+
+/** @} */
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
index 7c4be24..aedf369 100644
--- a/include/android/hardware_buffer_jni.h
+++ b/include/android/hardware_buffer_jni.h
@@ -15,7 +15,13 @@
  */
 
 /**
+ * @addtogroup AHardwareBuffer
+ * @{
+ */
+
+/**
  * @file hardware_buffer_jni.h
+ * @brief JNI glue for native hardware buffers.
  */
 
 #ifndef ANDROID_HARDWARE_BUFFER_JNI_H
@@ -30,23 +36,25 @@
 __BEGIN_DECLS
 
 /**
- * Return the AHardwareBuffer associated with a Java HardwareBuffer object,
- * for interacting with it through native code. This method does not acquire any
- * additional reference to the AHardwareBuffer that is returned. To keep the
- * AHardwareBuffer live after the Java HardwareBuffer object got garbage
- * collected, be sure to use AHardwareBuffer_acquire() to acquire an additional
- * reference.
+ * Return the AHardwareBuffer wrapped by a Java HardwareBuffer object.
+ *
+ * This method does not acquire any additional reference to the AHardwareBuffer
+ * that is returned. To keep the AHardwareBuffer live after the Java
+ * HardwareBuffer object got garbage collected, be sure to use AHardwareBuffer_acquire()
+ * to acquire an additional reference.
  */
 AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
-        jobject hardwareBufferObj);
+        jobject hardwareBufferObj) __INTRODUCED_IN(26);
 
 /**
  * Return a new Java HardwareBuffer object that wraps the passed native
  * AHardwareBuffer object.
  */
 jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env,
-        AHardwareBuffer* hardwareBuffer);
+        AHardwareBuffer* hardwareBuffer) __INTRODUCED_IN(26);
 
 __END_DECLS
 
 #endif // ANDROID_HARDWARE_BUFFER_JNI_H
+
+/** @} */
diff --git a/include/android/input.h b/include/android/input.h
index 0829989..cfade6c 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -56,6 +56,10 @@
 #include <android/keycodes.h>
 #include <android/looper.h>
 
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -79,7 +83,7 @@
 };
 
 /**
- * Meta key / modifer state.
+ * Meta key / modifier state.
  */
 enum {
     /** No meta keys are pressed. */
@@ -984,7 +988,7 @@
 
 #if __ANDROID_API__ >= 14
 /** Get the button state of all buttons that are pressed. */
-int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
+int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) __INTRODUCED_IN(14);
 #endif
 
 /**
@@ -1056,7 +1060,7 @@
  * The tool type indicates the type of tool used to make contact such as a
  * finger or stylus, if known.
  */
-int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
+int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) __INTRODUCED_IN(14);
 #endif
 
 /**
@@ -1150,7 +1154,7 @@
 #if __ANDROID_API__ >= 13
 /** Get the value of the request axis for the given pointer index. */
 float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index);
+        int32_t axis, size_t pointer_index) __INTRODUCED_IN(13);
 #endif
 
 /**
@@ -1288,7 +1292,7 @@
  * that occurred between this event and the previous motion event.
  */
 float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index, size_t history_index);
+        int32_t axis, size_t pointer_index, size_t history_index) __INTRODUCED_IN(13);
 #endif
 
 
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 59d67f3..214559d 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -769,7 +769,14 @@
     /** all apps */
     AKEYCODE_ALL_APPS = 284,
     /** refresh key */
-    AKEYCODE_REFRESH = 285
+    AKEYCODE_REFRESH = 285,
+    /** Thumbs up key. Apps can use this to let user upvote content. */
+    AKEYCODE_THUMBS_UP = 286,
+    /** Thumbs down key. Apps can use this to let user downvote content. */
+    AKEYCODE_THUMBS_DOWN = 287,
+    /** Used to switch current account that is consuming content.
+     * May be consumed by system to switch current viewer profile. */
+    AKEYCODE_PROFILE_SWITCH = 288
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 97892f8..d31d1f1 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
+/**
+ * @addtogroup Networking
+ * @{
+ */
+
+/**
+ * @file multinetwork.h
+ */
+
 #ifndef ANDROID_MULTINETWORK_H
 #define ANDROID_MULTINETWORK_H
 
@@ -51,7 +60,7 @@
  * on failure with an appropriate errno value set.
  */
 
-#if __ANDROID_API__ >= 24
+#if __ANDROID_API__ >= 23
 
 /**
  * Set the network to be used by the given socket file descriptor.
@@ -61,7 +70,7 @@
  * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket))
  *
  */
-int android_setsocknetwork(net_handle_t network, int fd);
+int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23);
 
 
 /**
@@ -78,7 +87,7 @@
  * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
  *
  */
-int android_setprocnetwork(net_handle_t network);
+int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23);
 
 
 /**
@@ -97,10 +106,80 @@
  */
 int android_getaddrinfofornetwork(net_handle_t network,
         const char *node, const char *service,
-        const struct addrinfo *hints, struct addrinfo **res);
+        const struct addrinfo *hints, struct addrinfo **res) __INTRODUCED_IN(23);
 
-#endif /* __ANDROID_API__ >= 24 */
+#endif /* __ANDROID_API__ >= 23 */
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * Possible values of the flags argument to android_res_nsend and android_res_nquery.
+ * Values are ORed together.
+ */
+enum ResNsendFlags : uint32_t {
+    /**
+     * Send a single request to a single resolver and fail on timeout or network errors
+     */
+    ANDROID_RESOLV_NO_RETRY = 1 << 0,
+
+    /**
+     * Do not cache the result of the lookup. The lookup may return a result that is already
+     * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+     */
+    ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
+
+    /**
+     * Don't lookup the request in cache.
+     */
+    ANDROID_RESOLV_NO_CACHE_LOOKUP = 1 << 2,
+};
+
+/**
+ * Look up the {|ns_class|, |ns_type|} Resource Record (RR) associated
+ * with Domain Name |dname| on the given |network|.
+ * The typical value for |ns_class| is ns_c_in, while |type| can be any
+ * record type (for instance, ns_t_aaaa or ns_t_txt).
+ * |flags| is a additional config to control actual querying behavior, see
+ * ResNsendFlags for detail.
+ *
+ * Returns a file descriptor to watch for read events, or a negative
+ * POSIX error code (see errno.h) if an immediate error occurs.
+ */
+int android_res_nquery(net_handle_t network,
+        const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
+
+/**
+ * Issue the query |msg| on the given |network|.
+ * |flags| is a additional config to control actual querying behavior, see
+ * ResNsendFlags for detail.
+ *
+ * Returns a file descriptor to watch for read events, or a negative
+ * POSIX error code (see errno.h) if an immediate error occurs.
+ */
+int android_res_nsend(net_handle_t network,
+        const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
+
+/**
+ * Read a result for the query associated with the |fd| descriptor.
+ * Closes |fd| before returning.
+ *
+ * Returns:
+ *     < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
+ *     >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain)
+ */
+int android_res_nresult(int fd,
+        int *rcode, uint8_t *answer, size_t anslen) __INTRODUCED_IN(29);
+
+/**
+ * Attempts to cancel the in-progress query associated with the |nsend_fd|
+ * descriptor.
+ */
+void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
 
 #endif  // ANDROID_MULTINETWORK_H
+
+/** @} */
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 23b39aa..0c196b9 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -44,16 +44,6 @@
  */
 ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
 
-#if __ANDROID_API__ >= 13
-/**
- * Return the ANativeWindow associated with a Java SurfaceTexture object,
- * for interacting with it through native code.  This acquires a reference
- * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
- * when done with it so that it doesn't leak.
- */
-ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture);
-#endif
-
 #if __ANDROID_API__ >= 26
 /**
  * Return a Java Surface object derived from the ANativeWindow, for interacting
@@ -62,7 +52,7 @@
  * and will automatically release the reference when the Java object gets garbage
  * collected.
  */
-jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window);
+jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26);
 #endif
 
 #ifdef __cplusplus
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 191777c..e9d5c16 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -64,6 +64,7 @@
 #define ASENSOR_RESOLUTION_INVALID     (nanf(""))
 #define ASENSOR_FIFO_COUNT_INVALID     (-1)
 #define ASENSOR_DELAY_INVALID          INT32_MIN
+#define ASENSOR_INVALID                (-1)
 
 /* (Keep in sync with hardware/sensors-base.h and Sensor.java.) */
 
@@ -208,6 +209,35 @@
      */
     ASENSOR_TYPE_HEART_BEAT = 31,
     /**
+     * This sensor type is for delivering additional sensor information aside
+     * from sensor event data.
+     *
+     * Additional information may include:
+     *     - {@link ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_SAMPLING}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY}
+     *     - {@link ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION}
+     *
+     * This type will never bind to a sensor. In other words, no sensor in the
+     * sensor list can have the type {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+     *
+     * If a device supports the sensor additional information feature, it will
+     * report additional information events via {@link ASensorEvent} and will
+     * have {@link ASensorEvent#type} set to
+     * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and {@link ASensorEvent#sensor} set
+     * to the handle of the reporting sensor.
+     *
+     * Additional information reports consist of multiple frames ordered by
+     * {@link ASensorEvent#timestamp}. The first frame in the report will have
+     * a {@link AAdditionalInfoEvent#type} of
+     * {@link ASENSOR_ADDITIONAL_INFO_BEGIN}, and the last frame in the report
+     * will have a {@link AAdditionalInfoEvent#type} of
+     * {@link ASENSOR_ADDITIONAL_INFO_END}.
+     *
+     */
+    ASENSOR_TYPE_ADDITIONAL_INFO = 33,
+    /**
      * {@link ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT}
      */
     ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT = 34,
@@ -273,6 +303,51 @@
     ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER = 2
 };
 
+/**
+ * Sensor Additional Info Types.
+ *
+ * Used to populate {@link AAdditionalInfoEvent#type}.
+ */
+enum {
+    /** Marks the beginning of additional information frames */
+    ASENSOR_ADDITIONAL_INFO_BEGIN = 0,
+
+    /** Marks the end of additional information frames */
+    ASENSOR_ADDITIONAL_INFO_END = 1,
+
+    /**
+     * Estimation of the delay that is not tracked by sensor timestamps. This
+     * includes delay introduced by sensor front-end filtering, data transport,
+     * etc.
+     * float[2]: delay in seconds, standard deviation of estimated value
+     */
+    ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY = 0x10000,
+
+    /** float: Celsius temperature */
+    ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE,
+
+    /**
+     * First three rows of a homogeneous matrix, which represents calibration to
+     * a three-element vector raw sensor reading.
+     * float[12]: 3x4 matrix in row major order
+     */
+    ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION,
+
+    /**
+     * Location and orientation of sensor element in the device frame: origin is
+     * the geometric center of the mobile device screen surface; the axis
+     * definition corresponds to Android sensor definitions.
+     * float[12]: 3x4 matrix in row major order
+     */
+    ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT,
+
+    /**
+     * float[2]: raw sample period in seconds,
+     *           standard deviation of sampling period
+     */
+    ASENSOR_ADDITIONAL_INFO_SAMPLING,
+};
+
 /*
  * A few useful constants
  */
@@ -341,7 +416,7 @@
     int32_t  handle;
 } ADynamicSensorEvent;
 
-typedef struct {
+typedef struct AAdditionalInfoEvent {
     int32_t type;
     int32_t serial;
     union {
@@ -420,6 +495,7 @@
  * - ASensorEventQueue_hasEvents()
  * - ASensorEventQueue_getEvents()
  * - ASensorEventQueue_setEventRate()
+ * - ASensorEventQueue_requestAdditionalInfoEvents()
  */
 typedef struct ASensorEventQueue ASensorEventQueue;
 
@@ -444,6 +520,7 @@
  * - ASensor_getStringType()
  * - ASensor_getReportingMode()
  * - ASensor_isWakeUpSensor()
+ * - ASensor_getHandle()
  */
 typedef struct ASensor ASensor;
 /**
@@ -472,13 +549,13 @@
  *     ASensorManager* sensorManager = ASensorManager_getInstance();
  *
  */
-#if __ANDROID_API__ >= __ANDROID_API_O__
+#if __ANDROID_API__ >= 26
 __attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance();
 #else
 ASensorManager* ASensorManager_getInstance();
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
+#if __ANDROID_API__ >= 26
 /**
  * Get a reference to the sensor manager. ASensorManager is a singleton
  * per package as different packages may have access to different sensors.
@@ -488,7 +565,7 @@
  *     ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
  *
  */
-ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
+ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
 #endif
 
 /**
@@ -507,7 +584,7 @@
  * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
  * of this type and wakeUp properties exists.
  */
-ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp);
+ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21);
 #endif
 
 /**
@@ -525,7 +602,7 @@
  */
 int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue);
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
+#if __ANDROID_API__ >= 26
 /**
  * Create direct channel based on shared memory
  *
@@ -542,7 +619,7 @@
  *         {@link ASensorManager_destroyDirectChannel} and
  *         {@link ASensorManager_configureDirectReport}, or value less or equal to 0 for failures.
  */
-int ASensorManager_createSharedMemoryDirectChannel(ASensorManager* manager, int fd, size_t size);
+int ASensorManager_createSharedMemoryDirectChannel(ASensorManager* manager, int fd, size_t size) __INTRODUCED_IN(26);
 
 /**
  * Create direct channel based on AHardwareBuffer
@@ -560,7 +637,7 @@
  *         {@link ASensorManager_configureDirectReport}, or value less or equal to 0 for failures.
  */
 int ASensorManager_createHardwareBufferDirectChannel(
-        ASensorManager* manager, AHardwareBuffer const * buffer, size_t size);
+        ASensorManager* manager, AHardwareBuffer const * buffer, size_t size) __INTRODUCED_IN(26);
 
 /**
  * Destroy a direct channel
@@ -575,7 +652,7 @@
  *                  {@link ASensorManager_createSharedMemoryDirectChannel} or
  *                  {@link ASensorManager_createHardwareBufferDirectChannel}.
  */
-void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId);
+void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) __INTRODUCED_IN(26);
 
 /**
  * Configure direct report on channel
@@ -612,9 +689,9 @@
  *
  * \return positive token for success or negative error code.
  */
-int ASensorManager_configureDirectReport(
-        ASensorManager* manager, ASensor const* sensor, int channelId, int rate);
-#endif
+int ASensorManager_configureDirectReport(ASensorManager* manager,
+        ASensor const* sensor, int channelId, int rate) __INTRODUCED_IN(26);
+#endif /* __ANDROID_API__ >= 26 */
 
 /*****************************************************************************/
 
@@ -703,6 +780,29 @@
  */
 ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
 
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on
+ * the given {@link ASensorEventQueue}.
+ *
+ * Sensor data events are always delivered to the {@ASensorEventQueue}.
+ *
+ * The {@link ASENSOR_TYPE_ADDITIONAL_INFO} events will be returned through
+ * {@link ASensorEventQueue_getEvents}. The client is responsible for checking
+ * {@link ASensorEvent#type} to determine the event type prior to handling of
+ * the event.
+ *
+ * The client must be tolerant of any value for
+ * {@link AAdditionalInfoEvent#type}, as new values may be defined in the future
+ * and may delivered to the client.
+ *
+ * \param queue {@link ASensorEventQueue} to configure
+ * \param enable true to request {@link ASENSOR_TYPE_ADDITIONAL_INFO} events,
+ *        false to stop receiving events
+ * \return 0 on success or a negative error code on failure
+ */
+int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable);
+#endif /* __ANDROID_API__ >= __ANDRDOID_API_Q__ */
 
 /*****************************************************************************/
 
@@ -738,30 +838,30 @@
  * Returns the maximum size of batches for this sensor. Batches will often be
  * smaller, as the hardware fifo might be used for other sensors.
  */
-int ASensor_getFifoMaxEventCount(ASensor const* sensor);
+int ASensor_getFifoMaxEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the hardware batch fifo size reserved to this sensor.
  */
-int ASensor_getFifoReservedEventCount(ASensor const* sensor);
+int ASensor_getFifoReservedEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns this sensor's string type.
  */
-const char* ASensor_getStringType(ASensor const* sensor);
+const char* ASensor_getStringType(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants.
  */
-int ASensor_getReportingMode(ASensor const* sensor);
+int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns true if this is a wake up sensor, false otherwise.
  */
-bool ASensor_isWakeUpSensor(ASensor const* sensor);
+bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21);
 #endif /* __ANDROID_API__ >= 21 */
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
+#if __ANDROID_API__ >= 26
 /**
  * Test if sensor supports a certain type of direct channel.
  *
@@ -771,7 +871,8 @@
  *                     or {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER}.
  * \returns true if sensor supports the specified direct channel type.
  */
-bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType);
+bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType) __INTRODUCED_IN(26);
+
 /**
  * Get the highest direct rate level that a sensor support.
  *
@@ -781,8 +882,26 @@
  *         If return value is {@link ASENSOR_DIRECT_RATE_STOP}, it means the sensor
  *         does not support direct report.
  */
-int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor);
-#endif
+int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
+#endif /* __ANDROID_API__ >= 26 */
+
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Returns the sensor's handle.
+ *
+ * The handle identifies the sensor within the system and is included in the
+ * {@link ASensorEvent#sensor} field of sensor events, including those sent with type
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+ *
+ * A sensor's handle is able to be used to map {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to the
+ * sensor that generated the event.
+ *
+ * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
+ * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
+ * between the values.
+ */
+int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__);
+#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 46d2f4b..7f5177b 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -21,12 +21,14 @@
 
 /**
  * @file sharedmem.h
+ * @brief Shared memory buffers that can be shared across process.
  */
 
 #ifndef ANDROID_SHARED_MEMORY_H
 #define ANDROID_SHARED_MEMORY_H
 
 #include <stddef.h>
+#include <sys/cdefs.h>
 
 /******************************************************************
  *
@@ -44,15 +46,11 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-/**
- * Structures and functions for a shared memory buffer that can be shared across process.
- */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
+#if __ANDROID_API__ >= 26
 
 /**
  * Create a shared memory region.
@@ -63,19 +61,23 @@
  *
  * Use close() to release the shared memory region.
  *
+ * Available since API level 26.
+ *
  * \param name an optional name.
  * \param size size of the shared memory region
  * \return file descriptor that denotes the shared memory; error code on failure.
  */
-int ASharedMemory_create(const char *name, size_t size);
+int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26);
 
 /**
  * Get the size of the shared memory region.
  *
+ * Available since API level 26.
+ *
  * \param fd file descriptor of the shared memory region
  * \return size in bytes; 0 if fd is not a valid shared memory file descriptor.
  */
-size_t ASharedMemory_getSize(int fd);
+size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26);
 
 /**
  * Restrict access of shared memory region.
@@ -92,7 +94,8 @@
  *     int fd = ASharedMemory_create("memory", 128);
  *
  *     // By default it has PROT_READ | PROT_WRITE | PROT_EXEC.
- *     char *buffer = (char *) mmap(NULL, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ *     size_t memSize = ASharedMemory_getSize(fd);
+ *     char *buffer = (char *) mmap(NULL, memSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  *
  *     strcpy(buffer, "This is an example."); // trivially initialize content
  *
@@ -101,14 +104,16 @@
  *
  *     // share fd with another process here and the other process can only map with PROT_READ.
  *
+ * Available since API level 26.
+ *
  * \param fd   file descriptor of the shared memory region.
  * \param prot any bitwise-or'ed combination of PROT_READ, PROT_WRITE, PROT_EXEC denoting
  *             updated access. Note access can only be removed, but not added back.
  * \return 0 for success, error code on failure.
  */
-int ASharedMemory_setProt(int fd, int prot);
+int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26);
 
-#endif
+#endif // __ANDROID_API__ >= 26
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
index 85ac78f..13e56e6 100644
--- a/include/android/sharedmem_jni.h
+++ b/include/android/sharedmem_jni.h
@@ -21,6 +21,7 @@
 
 /**
  * @file sharedmem_jni.h
+ * @brief Shared memory buffers that can be shared across process.
  */
 
 #ifndef ANDROID_SHARED_MEMORY_JNI_H
@@ -29,6 +30,7 @@
 #include <jni.h>
 #include <android/sharedmem.h>
 #include <stddef.h>
+#include <sys/cdefs.h>
 
 /******************************************************************
  *
@@ -46,15 +48,11 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-/**
- * Structures and functions for a shared memory buffer that can be shared across process.
- */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_O_MR1__
+#if __ANDROID_API__ >= 27
 
 /**
  * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file
@@ -64,15 +62,17 @@
  *
  * Use close() to release the shared memory region.
  *
+ * Available since API level 27.
+ *
  * \param env The JNIEnv* pointer
  * \param sharedMemory The Java android.os.SharedMemory object
  * \return file descriptor that denotes the shared memory; -1 if the shared memory object is
  *      already closed, if the JNIEnv or jobject is NULL, or if there are too many open file
  *      descriptors (errno=EMFILE)
  */
-int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory);
+int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory) __INTRODUCED_IN(27);
 
-#endif
+#endif // __ANDROID_API__ >= 27
 
 #ifdef __cplusplus
 };
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
new file mode 100644
index 0000000..ef2ad99
--- /dev/null
+++ b/include/android/surface_control.h
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NativeActivity Native Activity
+ * @{
+ */
+
+/**
+ * @file surface_control.h
+ */
+
+#ifndef ANDROID_SURFACE_CONTROL_H
+#define ANDROID_SURFACE_CONTROL_H
+
+#include <sys/cdefs.h>
+
+#include <android/data_space.h>
+#include <android/hardware_buffer.h>
+#include <android/hdr_metadata.h>
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+struct ASurfaceControl;
+
+/**
+ * The SurfaceControl API can be used to provide a hierarchy of surfaces for
+ * composition to the system compositor. ASurfaceControl represents a content node in
+ * this hierarchy.
+ */
+typedef struct ASurfaceControl ASurfaceControl;
+
+/*
+ * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent.
+ * |debug_name| is a debug name associated with this surface. It can be used to
+ * identify this surface in the SurfaceFlinger's layer tree. It must not be
+ * null.
+ *
+ * The caller takes ownership of the ASurfaceControl returned and must release it
+ * using ASurfaceControl_release below.
+ */
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
+                                                  __INTRODUCED_IN(29);
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
+                                        __INTRODUCED_IN(29);
+
+/**
+ * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer
+ * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
+ * as their parent remains on display.
+ */
+void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
+
+struct ASurfaceTransaction;
+
+/**
+ * ASurfaceTransaction is a collection of updates to the surface tree that must
+ * be applied atomically.
+ */
+typedef struct ASurfaceTransaction ASurfaceTransaction;
+
+/**
+ * The caller takes ownership of the transaction and must release it using
+ * ASurfaceControl_delete below.
+ */
+ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
+
+/**
+ * Destroys the |transaction| object.
+ */
+void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * Applies the updates accumulated in |transaction|.
+ *
+ * Note that the transaction is guaranteed to be applied atomically. The
+ * transactions which are applied on the same thread are also guaranteed to be
+ * applied in order.
+ */
+void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * An opaque handle returned during a callback that can be used to query general stats and stats for
+ * surfaces which were either removed or for which buffers were updated after this transaction was
+ * applied.
+ */
+typedef struct ASurfaceTransactionStats ASurfaceTransactionStats;
+
+/**
+ * Since the transactions are applied asynchronously, the
+ * ASurfaceTransaction_OnComplete callback can be used to be notified when a frame
+ * including the updates in a transaction was presented.
+ *
+ * |context| is the optional context provided by the client that is passed into
+ * the callback.
+ *
+ * |stats| is an opaque handle that can be passed to ASurfaceTransactionStats functions to query
+ * information about the transaction. The handle is only valid during the callback.
+ *
+ * THREADING
+ * The transaction completed callback can be invoked on any thread.
+ */
+typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
+                                               __INTRODUCED_IN(29);
+
+/**
+ * Returns the timestamp of when the frame was latched by the framework. Once a frame is
+ * latched by the framework, it is presented at the following hardware vsync.
+ */
+int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats)
+                                              __INTRODUCED_IN(29);
+
+/**
+ * Returns a sync fence that signals when the transaction has been presented.
+ * The recipient of the callback takes ownership of the fence and is responsible for closing
+ * it.
+ */
+int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
+                                               __INTRODUCED_IN(29);
+
+/**
+ * |outASurfaceControls| returns an array of ASurfaceControl pointers that were updated during the
+ * transaction. Stats for the surfaces can be queried through ASurfaceTransactionStats functions.
+ * When the client is done using the array, it must release it by calling
+ * ASurfaceTransactionStats_releaseASurfaceControls.
+ *
+ * |outASurfaceControlsSize| returns the size of the ASurfaceControls array.
+ */
+void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats,
+                                                  ASurfaceControl*** outASurfaceControls,
+                                                  size_t* outASurfaceControlsSize)
+                                                  __INTRODUCED_IN(29);
+/**
+ * Releases the array of ASurfaceControls that were returned by
+ * ASurfaceTransactionStats_getASurfaceControls.
+ */
+void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls)
+                                                      __INTRODUCED_IN(29);
+
+/**
+ * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered
+ * acquired when its acquire_fence_fd has signaled. A buffer cannot be latched or presented until
+ * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1.
+ */
+int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats,
+                                                ASurfaceControl* surface_control)
+                                                __INTRODUCED_IN(29);
+
+/**
+ * The returns the fence used to signal the release of the PREVIOUS buffer set on
+ * this surface. If this fence is valid (>=0), the PREVIOUS buffer has not yet been released and the
+ * fence will signal when the PREVIOUS buffer has been released. If the fence is -1 , the PREVIOUS
+ * buffer is already released. The recipient of the callback takes ownership of the
+ * previousReleaseFenceFd and is responsible for closing it.
+ *
+ * Each time a buffer is set through ASurfaceTransaction_setBuffer()/_setCachedBuffer() on a
+ * transaction which is applied, the framework takes a ref on this buffer. The framework treats the
+ * addition of a buffer to a particular surface as a unique ref. When a transaction updates or
+ * removes a buffer from a surface, or removes the surface itself from the tree, this ref is
+ * guaranteed to be released in the OnComplete callback for this transaction. The
+ * ASurfaceControlStats provided in the callback for this surface may contain an optional fence
+ * which must be signaled before the ref is assumed to be released.
+ *
+ * The client must ensure that all pending refs on a buffer are released before attempting to reuse
+ * this buffer, otherwise synchronization errors may occur.
+ */
+int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
+                                                ASurfaceTransactionStats* surface_transaction_stats,
+                                                ASurfaceControl* surface_control)
+                                                __INTRODUCED_IN(29);
+
+/**
+ * Sets the callback that will be invoked when the updates from this transaction
+ * are presented. For details on the callback semantics and data, see the
+ * comments on the ASurfaceTransaction_OnComplete declaration above.
+ */
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
+                                       ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
+
+/**
+ * Reparents the |surface_control| from its old parent to the |new_parent| surface control.
+ * Any children of the* reparented |surface_control| will remain children of the |surface_control|.
+ *
+ * The |new_parent| can be null. Surface controls with a null parent do not appear on the display.
+ */
+void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction,
+                                  ASurfaceControl* surface_control, ASurfaceControl* new_parent)
+                                  __INTRODUCED_IN(29);
+
+/* Parameter for ASurfaceTransaction_setVisibility */
+enum {
+    ASURFACE_TRANSACTION_VISIBILITY_HIDE = 0,
+    ASURFACE_TRANSACTION_VISIBILITY_SHOW = 1,
+};
+/**
+ * Updates the visibility of |surface_control|. If show is set to
+ * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will
+ * be hidden.
+ */
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
+                                       ASurfaceControl* surface_control, int8_t visibility)
+                                       __INTRODUCED_IN(29);
+
+/**
+ * Updates the z order index for |surface_control|. Note that the z order for a surface
+ * is relative to other surfaces which are siblings of this surface. The behavior of sibilings with
+ * the same z order is undefined.
+ *
+ * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0.
+ */
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
+                                   ASurfaceControl* surface_control, int32_t z_order)
+                                   __INTRODUCED_IN(29);
+
+/**
+ * Updates the AHardwareBuffer displayed for |surface_control|. If not -1, the
+ * acquire_fence_fd should be a file descriptor that is signaled when all pending work
+ * for the buffer is complete and the buffer can be safely read.
+ *
+ * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible
+ * for closing it.
+ */
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
+                                   ASurfaceControl* surface_control, AHardwareBuffer* buffer,
+                                   int acquire_fence_fd = -1) __INTRODUCED_IN(29);
+
+/**
+ * Updates the color for |surface_control|.  This will make the background color for the
+ * ASurfaceControl visible in transparent regions of the surface.  Colors |r|, |g|,
+ * and |b| must be within the range that is valid for |dataspace|.  |dataspace| and |alpha|
+ * will be the dataspace and alpha set for the background color layer.
+ */
+void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction,
+                                  ASurfaceControl* surface_control, float r, float g, float b,
+                                  float alpha, ADataSpace dataspace)
+                                  __INTRODUCED_IN(29);
+
+/**
+ * |source| the sub-rect within the buffer's content to be rendered inside the surface's area
+ * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
+ * and height must be > 0.
+ *
+ * |destination| specifies the rect in the parent's space where this surface will be drawn. The post
+ * source rect bounds are scaled to fit the destination rect. The surface's destination rect is
+ * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
+ *
+ * |transform| the transform applied after the source rect is applied to the buffer. This parameter
+ * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
+ * enum.
+ */
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
+                                     ASurfaceControl* surface_control, const ARect& source,
+                                     const ARect& destination, int32_t transform)
+                                     __INTRODUCED_IN(29);
+
+
+/* Parameter for ASurfaceTransaction_setBufferTransparency */
+enum {
+    ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0,
+    ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1,
+    ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
+};
+/**
+ * Updates whether the content for the buffer associated with this surface is
+ * completely opaque. If true, every pixel of content inside the buffer must be
+ * opaque or visual errors can occur.
+ */
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
+                                               ASurfaceControl* surface_control,
+                                               int8_t transparency)
+                                               __INTRODUCED_IN(29);
+
+/**
+ * Updates the region for the content on this surface updated in this
+ * transaction. If unspecified, the complete surface is assumed to be damaged.
+ */
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
+                                         ASurfaceControl* surface_control, const ARect rects[],
+                                         uint32_t count) __INTRODUCED_IN(29);
+
+/**
+ * Specifies a desiredPresentTime for the transaction. The framework will try to present
+ * the transaction at or after the time specified.
+ *
+ * Transactions will not be presented until all of their acquire fences have signaled even if the
+ * app requests an earlier present time.
+ *
+ * If an earlier transaction has a desired present time of x, and a later transaction has a desired
+ * present time that is before x, the later transaction will not preempt the earlier transaction.
+ */
+void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction,
+                                               int64_t desiredPresentTime) __INTRODUCED_IN(29);
+
+/**
+ * Sets the alpha for the buffer. It uses a premultiplied blending.
+ *
+ * The |alpha| must be between 0.0 and 1.0.
+ */
+void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction,
+                                        ASurfaceControl* surface_control, float alpha)
+                                        __INTRODUCED_IN(29);
+
+/**
+ * Sets the data space of the surface_control's buffers.
+ *
+ * If no data space is set, the surface control defaults to ADATASPACE_SRGB.
+ */
+void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction,
+                                            ASurfaceControl* surface_control, ADataSpace data_space)
+                                            __INTRODUCED_IN(29);
+
+/*
+ * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
+ *
+ * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering
+ * the surface's buffer.
+ */
+void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction,
+                                                  ASurfaceControl* surface_control,
+                                                  struct AHdrMetadata_smpte2086* metadata)
+                                                  __INTRODUCED_IN(29);
+
+/*
+ * Sets the CTA 861.3 "HDR Static Metadata Extension" static metadata on a surface.
+ *
+ * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering
+ * the surface's buffer.
+ */
+void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction,
+                                                 ASurfaceControl* surface_control,
+                                                 struct AHdrMetadata_cta861_3* metadata)
+                                                 __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index 56b3342..540d23a 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -43,6 +43,7 @@
  */
 
 #include <stdint.h>
+#include <sys/cdefs.h>
 
 #include <android/native_window.h>
 
@@ -58,13 +59,15 @@
  */
 typedef struct ASurfaceTexture ASurfaceTexture;
 
+#if __ANDROID_API__ >= 28
+
 /**
  * Release the reference to the native ASurfaceTexture acquired with
  * ASurfaceTexture_fromSurfaceTexture().
  * Failing to do so will result in leaked memory and graphic resources.
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
-void ASurfaceTexture_release(ASurfaceTexture* st);
+void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
@@ -73,9 +76,9 @@
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed
  * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
- * returned if \st is null or if it's not an instance of android.graphics.SurfaceTexture
+ * returned if \p st is null or if it's not an instance of android.graphics.SurfaceTexture
  */
-ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st);
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread.  A
@@ -92,7 +95,7 @@
  * must be unusued in the OpenGL ES context that is current on the calling thread.
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
-int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName);
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) __INTRODUCED_IN(28);
 
 /**
  * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
@@ -108,7 +111,7 @@
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
-int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st);
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Update the texture image to the most recent frame from the image stream.  This may only be
@@ -118,7 +121,7 @@
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
-int ASurfaceTexture_updateTexImage(ASurfaceTexture* st);
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
@@ -136,7 +139,7 @@
  * \param mtx the array into which the 4x4 matrix will be stored.  The array must have exactly
  *     16 elements.
  */
-void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) __INTRODUCED_IN(28);
 
 /**
  * Retrieve the timestamp associated with the texture image set by the most recent call to
@@ -155,7 +158,9 @@
  *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
-int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st);
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28);
+
+#endif /* __ANDROID_API__ >= 28 */
 
 __END_DECLS
 
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
new file mode 100644
index 0000000..dde9055
--- /dev/null
+++ b/include/android/system_fonts.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup Font
+ * {
+ */
+
+/**
+ * @file system_fonts.h
+ * @brief Provides the system font configurations.
+ *
+ * These APIs provides the list of system installed font files with additional metadata about the
+ * font.
+ *
+ * The ASystemFontIterator_open method will give you an iterator which can iterate all system
+ * installed font files as shown in the following example.
+ *
+ * \code{.cpp}
+ *   ASystemFontIterator* iterator = ASystemFontIterator_open();
+ *   ASystemFont* font = NULL;
+ *
+ *   while ((font = ASystemFontIterator_next(iterator)) != nullptr) {
+ *       // Look if the font is your desired one.
+ *       if (ASystemFont_getWeight(font) == 400 && !ASystemFont_isItalic(font)
+ *           && ASystemFont_getLocale(font) == NULL) {
+ *           break;
+ *       }
+ *       ASystemFont_close(font);
+ *   }
+ *   ASystemFontIterator_close(iterator);
+ *
+ *   int fd = open(ASystemFont_getFontFilePath(font), O_RDONLY);
+ *   int collectionIndex = ASystemFont_getCollectionINdex(font);
+ *   std::vector<std::pair<uint32_t, float>> variationSettings;
+ *   for (size_t i = 0; i < ASystemFont_getAxisCount(font); ++i) {
+ *       variationSettings.push_back(std::make_pair(
+ *           ASystemFont_getAxisTag(font, i),
+ *           ASystemFont_getAxisValue(font, i)));
+ *   }
+ *   ASystemFont_close(font);
+ *
+ *   // Use this font for your text rendering engine.
+ *
+ * \endcode
+ *
+ * Available since API level 29.
+ */
+
+#ifndef ANDROID_SYSTEM_FONTS_H
+#define ANDROID_SYSTEM_FONTS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+#include <android/font.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * ASystemFontIterator provides access to the system font configuration.
+ *
+ * ASystemFontIterator is an iterator for all available system font settings.
+ * This iterator is not a thread-safe object. Do not pass this iterator to other threads.
+ */
+struct ASystemFontIterator;
+
+/**
+ * Create a system font iterator.
+ *
+ * Use ASystemFont_close() to close the iterator.
+ *
+ * \return a pointer for a newly allocated iterator, nullptr on failure.
+ */
+ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29);
+
+/**
+ * Close an opened system font iterator, freeing any related resources.
+ *
+ * \param iterator a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
+ */
+void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
+
+/**
+ * Move to the next system font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a font. If no more font is available, returns nullptr. You need to release the returned
+ *         font by ASystemFont_close when it is no longer needed.
+ */
+AFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SYSTEM_FONTS_H
+
+/** @} */
diff --git a/include/android/trace.h b/include/android/trace.h
index d3b1fb6..bb7ff28 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -15,17 +15,25 @@
  */
 
 /**
+ * @addtogroup Tracing
+ * @{
+ */
+
+/**
  * @file trace.h
  * @brief Writes trace events to the system trace buffer.
  *
  * These trace events can be collected and visualized using the Systrace tool.
  * For information about using the Systrace tool, read <a href="https://developer.android.com/studio/profile/systrace.html">Analyzing UI Performance with Systrace</a>.
+ *
+ * Available since API level 23.
  */
 
 #ifndef ANDROID_NATIVE_TRACE_H
 #define ANDROID_NATIVE_TRACE_H
 
 #include <stdbool.h>
+#include <stdint.h>
 #include <sys/cdefs.h>
 
 #ifdef __cplusplus
@@ -35,33 +43,75 @@
 #if __ANDROID_API__ >= 23
 
 /**
- * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary
+ * Returns true if tracing is enabled. Use this to avoid expensive computation only necessary
  * when tracing is enabled.
+ *
+ * Available since API level 23.
  */
-bool ATrace_isEnabled();
+bool ATrace_isEnabled() __INTRODUCED_IN(23);
 
 /**
  * Writes a tracing message to indicate that the given section of code has begun. This call must be
- * followed by a corresponding call to endSection() on the same thread.
+ * followed by a corresponding call to {@link ATrace_endSection} on the same thread.
  *
- * Note: At this time the vertical bar character '|' and newline character '\n' are used internally
- * by the tracing mechanism. If sectionName contains these characters they will be replaced with a
+ * Note: At this time the vertical bar character '|' and newline character '\\n' are used internally
+ * by the tracing mechanism. If \p sectionName contains these characters they will be replaced with a
  * space character in the trace.
+ *
+ * Available since API level 23.
  */
-void ATrace_beginSection(const char* sectionName);
+void ATrace_beginSection(const char* sectionName) __INTRODUCED_IN(23);
 
 /**
  * Writes a tracing message to indicate that a given section of code has ended. This call must be
- * preceeded by a corresponding call to beginSection(char*) on the same thread. Calling this method
+ * preceeded by a corresponding call to {@link ATrace_beginSection} on the same thread. Calling this method
  * will mark the end of the most recently begun section of code, so care must be taken to ensure
- * that beginSection / endSection pairs are properly nested and called from the same thread.
+ * that {@link ATrace_beginSection}/{@link ATrace_endSection} pairs are properly nested and called from the same thread.
+ *
+ * Available since API level 23.
  */
-void ATrace_endSection();
+void ATrace_endSection() __INTRODUCED_IN(23);
 
 #endif /* __ANDROID_API__ >= 23 */
 
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+/**
+ * Writes a trace message to indicate that a given section of code has
+ * begun. Must be followed by a call to {@link ATrace_endAsyncSection} with the same
+ * methodName and cookie. Unlike {@link ATrace_beginSection} and {@link ATrace_endSection},
+ * asynchronous events do not need to be nested. The name and cookie used to
+ * begin an event must be used to end it.
+ *
+ * \param sectionName The method name to appear in the trace.
+ * \param cookie Unique identifier for distinguishing simultaneous events
+ */
+void ATrace_beginAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCED_IN(29);
+
+/**
+ * Writes a trace message to indicate that the current method has ended.
+ * Must be called exactly once for each call to {@link ATrace_beginAsyncSection}
+ * using the same name and cookie.
+ *
+ * \param methodName The method name to appear in the trace.
+ * \param cookie Unique identifier for distinguishing simultaneous events
+ */
+void ATrace_endAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCED_IN(29);
+
+/**
+ * Writes trace message to indicate the value of a given counter.
+ *
+ * \param counterName The counter name to appear in the trace.
+ * \param counterValue The counter value.
+ */
+void ATrace_setCounter(const char* counterName, int64_t counterValue) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
 #ifdef __cplusplus
 };
 #endif
 
 #endif // ANDROID_NATIVE_TRACE_H
+
+/** @} */
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 009dc52..639df7a 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -20,7 +20,6 @@
 namespace android {
 
 // must be kept in sync with definitions in AudioPlaybackConfiguration.java
-
 #define PLAYER_PIID_INVALID -1
 
 typedef enum {
@@ -40,6 +39,15 @@
     PLAYER_STATE_STOPPED  = 4,
 } player_state_t;
 
+// must be kept in sync with definitions in AudioManager.java
+#define RECORD_RIID_INVALID -1
+
+typedef enum {
+    RECORDER_STATE_UNKNOWN  = -1,
+    RECORDER_STATE_STARTED  = 0,
+    RECORDER_STATE_STOPPED  = 1,
+} recorder_state_t;
+
 }; // namespace android
 
 #endif // ANDROID_AUDIOMANAGER_H
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index d279bbd..2f5ccb8 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -36,6 +36,9 @@
         PLAYER_ATTRIBUTES                     = IBinder::FIRST_CALL_TRANSACTION + 1,
         PLAYER_EVENT                          = IBinder::FIRST_CALL_TRANSACTION + 2,
         RELEASE_PLAYER                        = IBinder::FIRST_CALL_TRANSACTION + 3,
+        TRACK_RECORDER                        = IBinder::FIRST_CALL_TRANSACTION + 4,
+        RECORDER_EVENT                        = IBinder::FIRST_CALL_TRANSACTION + 5,
+        RELEASE_RECORDER                      = IBinder::FIRST_CALL_TRANSACTION + 6,
     };
 
     DECLARE_META_INTERFACE(AudioManager)
@@ -48,6 +51,9 @@
                 audio_content_type_t content)= 0;
     /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) = 0;
     /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
+    virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
+    /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
+    /*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/batteryservice b/include/batteryservice
deleted file mode 120000
index 2178c32..0000000
--- a/include/batteryservice
+++ /dev/null
@@ -1 +0,0 @@
-../services/batteryservice/include/batteryservice/
\ No newline at end of file
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 86da4d3..fa456bb 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,11 +17,39 @@
 #ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
 #define _LIBINPUT_DISPLAY_VIEWPORT_H
 
+#include <android-base/stringprintf.h>
 #include <ui/DisplayInfo.h>
 #include <input/Input.h>
+#include <inttypes.h>
+#include <optional>
+
+using android::base::StringPrintf;
 
 namespace android {
 
+/**
+ * Describes the different type of viewports supported by input flinger.
+ * Keep in sync with values in InputManagerService.java.
+ */
+enum class ViewportType : int32_t {
+    VIEWPORT_INTERNAL = 1,
+    VIEWPORT_EXTERNAL = 2,
+    VIEWPORT_VIRTUAL = 3,
+};
+
+static const char* viewportTypeToString(ViewportType type) {
+    switch(type) {
+        case ViewportType::VIEWPORT_INTERNAL:
+            return "INTERNAL";
+        case ViewportType::VIEWPORT_EXTERNAL:
+            return "EXTERNAL";
+        case ViewportType::VIEWPORT_VIRTUAL:
+            return "VIRTUAL";
+        default:
+            return "UNKNOWN";
+    }
+}
+
 /*
  * Describes how coordinates are mapped on a physical display.
  * See com.android.server.display.DisplayViewport.
@@ -39,13 +67,18 @@
     int32_t physicalBottom;
     int32_t deviceWidth;
     int32_t deviceHeight;
-    String8 uniqueId;
+    std::string uniqueId;
+    // The actual (hardware) port that the associated display is connected to.
+    // Not all viewports will have this specified.
+    std::optional<uint8_t> physicalPort;
+    ViewportType type;
 
     DisplayViewport() :
             displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
             logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
             physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
-            deviceWidth(0), deviceHeight(0) {
+            deviceWidth(0), deviceHeight(0), uniqueId(), physicalPort(std::nullopt),
+            type(ViewportType::VIEWPORT_INTERNAL) {
     }
 
     bool operator==(const DisplayViewport& other) const {
@@ -61,7 +94,9 @@
                 && physicalBottom == other.physicalBottom
                 && deviceWidth == other.deviceWidth
                 && deviceHeight == other.deviceHeight
-                && uniqueId == other.uniqueId;
+                && uniqueId == other.uniqueId
+                && physicalPort == other.physicalPort
+                && type == other.type;
     }
 
     bool operator!=(const DisplayViewport& other) const {
@@ -86,17 +121,25 @@
         deviceWidth = width;
         deviceHeight = height;
         uniqueId.clear();
+        physicalPort = std::nullopt;
+        type = ViewportType::VIEWPORT_INTERNAL;
     }
-};
 
-/**
- * Describes the different type of viewports supported by input flinger.
- * Keep in sync with values in InputManagerService.java.
- */
-enum class ViewportType : int32_t {
-    VIEWPORT_INTERNAL = 1,
-    VIEWPORT_EXTERNAL = 2,
-    VIEWPORT_VIRTUAL = 3,
+    std::string toString() const {
+        return StringPrintf("Viewport %s: displayId=%d, uniqueId=%s, port=%s, orientation=%d, "
+            "logicalFrame=[%d, %d, %d, %d], "
+            "physicalFrame=[%d, %d, %d, %d], "
+            "deviceSize=[%d, %d]",
+            viewportTypeToString(type), displayId,
+            uniqueId.c_str(),
+            physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str() : "<none>",
+            orientation,
+            logicalLeft, logicalTop,
+            logicalRight, logicalBottom,
+            physicalLeft, physicalTop,
+            physicalRight, physicalBottom,
+            deviceWidth, deviceHeight);
+    }
 };
 
 } // namespace android
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 11bb721..4365a3c 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -22,6 +22,9 @@
 
 #include <binder/IInterface.h>
 
+#include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
+
 namespace android {
 
 /*
@@ -31,6 +34,12 @@
 class IInputFlinger : public IInterface {
 public:
     DECLARE_META_INTERFACE(InputFlinger)
+
+    virtual void setInputWindows(const std::vector<InputWindowInfo>& inputHandles,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
+    virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
+    virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
+    virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
 };
 
 
@@ -40,7 +49,10 @@
 class BnInputFlinger : public BnInterface<IInputFlinger> {
 public:
     enum {
-        DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        REGISTER_INPUT_CHANNEL_TRANSACTION,
+        UNREGISTER_INPUT_CHANNEL_TRANSACTION,
+        TRANSFER_TOUCH_FOCUS
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/ISetInputWindowsListener.h b/include/input/ISetInputWindowsListener.h
new file mode 100644
index 0000000..15d31b2
--- /dev/null
+++ b/include/input/ISetInputWindowsListener.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class ISetInputWindowsListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(SetInputWindowsListener)
+    virtual void onSetInputWindowsFinished() = 0;
+};
+
+class BnSetInputWindowsListener: public BnInterface<ISetInputWindowsListener> {
+public:
+    enum SetInputWindowsTag : uint32_t {
+        ON_SET_INPUT_WINDOWS_FINISHED
+    };
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0) override;
+};
+
+}; // namespace android
diff --git a/include/input/Input.h b/include/input/Input.h
index cfcafab..805957a 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -17,6 +17,8 @@
 #ifndef _LIBINPUT_INPUT_H
 #define _LIBINPUT_INPUT_H
 
+#pragma GCC system_header
+
 /**
  * Native input event structures.
  */
@@ -25,7 +27,6 @@
 #include <utils/BitSet.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
 #include <stdint.h>
@@ -58,6 +59,12 @@
      */
     AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2,
 
+    /**
+     * This flag indicates that the event has been generated by a gesture generator. It
+     * provides a hint to the GestureDetector to not apply any touch slop.
+     */
+    AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8,
+
     /* Motion event is inconsistent with previously sent motion events. */
     AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
 };
@@ -213,6 +220,32 @@
     POLICY_FLAG_PASS_TO_USER = 0x40000000,
 };
 
+/**
+ * Classifications of the current gesture, if available.
+ *
+ * The following values must be kept in sync with MotionEvent.java
+ */
+enum class MotionClassification : uint8_t {
+    /**
+     * No classification is available.
+     */
+    NONE = 0,
+    /**
+     * Too early to classify the current gesture. Need more events. Look for changes in the
+     * upcoming motion events.
+     */
+    AMBIGUOUS_GESTURE = 1,
+    /**
+     * The current gesture likely represents a user intentionally exerting force on the touchscreen.
+     */
+    DEEP_PRESS = 2,
+};
+
+/**
+ * String representation of MotionClassification
+ */
+const char* motionClassificationToString(MotionClassification classification);
+
 /*
  * Pointer coordinate data.
  */
@@ -237,7 +270,12 @@
     float getAxisValue(int32_t axis) const;
     status_t setAxisValue(int32_t axis, float value);
 
-    void scale(float scale);
+    void scale(float globalScale);
+
+    // Scale the pointer coordinates according to a global scale and a
+    // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
+    // axes, however the window scaling will not.
+    void scale(float globalScale, float windowXScale, float windowYScale);
     void applyOffset(float xOffset, float yOffset);
 
     inline float getX() const {
@@ -302,12 +340,18 @@
 
     inline void setSource(int32_t source) { mSource = source; }
 
+    inline int32_t getDisplayId() const { return mDisplayId; }
+
+    inline void setDisplayId(int32_t displayId) { mDisplayId = displayId; }
+
+
 protected:
-    void initialize(int32_t deviceId, int32_t source);
+    void initialize(int32_t deviceId, int32_t source, int32_t displayId);
     void initialize(const InputEvent& from);
 
     int32_t mDeviceId;
     int32_t mSource;
+    int32_t mDisplayId;
 };
 
 /*
@@ -339,10 +383,11 @@
 
     static const char* getLabel(int32_t keyCode);
     static int32_t getKeyCodeFromLabel(const char* label);
-    
+
     void initialize(
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t flags,
             int32_t keyCode,
@@ -400,6 +445,8 @@
 
     inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
 
+    inline MotionClassification getClassification() const { return mClassification; }
+
     inline int32_t getActionButton() const { return mActionButton; }
 
     inline void setActionButton(int32_t button) { mActionButton = button; }
@@ -556,12 +603,14 @@
     void initialize(
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t actionButton,
             int32_t flags,
             int32_t edgeFlags,
             int32_t metaState,
             int32_t buttonState,
+            MotionClassification classification,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -580,7 +629,7 @@
 
     void offsetLocation(float xOffset, float yOffset);
 
-    void scale(float scaleFactor);
+    void scale(float globalScaleFactor);
 
     // Apply 3x3 perspective matrix transformation.
     // Matrix is in row-major form and compatible with SkMatrix.
@@ -615,6 +664,7 @@
     int32_t mEdgeFlags;
     int32_t mMetaState;
     int32_t mButtonState;
+    MotionClassification mClassification;
     float mXOffset;
     float mYOffset;
     float mXPrecision;
@@ -661,7 +711,7 @@
  */
 class PooledInputEventFactory : public InputEventFactoryInterface {
 public:
-    PooledInputEventFactory(size_t maxPoolSize = 20);
+    explicit PooledInputEventFactory(size_t maxPoolSize = 20);
     virtual ~PooledInputEventFactory();
 
     virtual KeyEvent* createKeyEvent();
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
new file mode 100644
index 0000000..7f04611
--- /dev/null
+++ b/include/input/InputApplication.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 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 _UI_INPUT_APPLICATION_H
+#define _UI_INPUT_APPLICATION_H
+
+#include <string>
+
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
+#include <input/Input.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+/*
+ * Describes the properties of an application that can receive input.
+ */
+struct InputApplicationInfo {
+    sp<IBinder> token;
+    std::string name;
+    nsecs_t dispatchingTimeout;
+
+    status_t write(Parcel& output) const;
+    static InputApplicationInfo read(const Parcel& from);
+};
+
+
+/*
+ * Handle for an application that can receive input.
+ *
+ * Used by the native input dispatcher as a handle for the window manager objects
+ * that describe an application.
+ */
+class InputApplicationHandle : public RefBase {
+public:
+    inline const InputApplicationInfo* getInfo() const {
+        return &mInfo;
+    }
+
+    inline std::string getName() const {
+        return !mInfo.name.empty() ? mInfo.name : "<invalid>";
+    }
+
+    inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
+        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
+    }
+
+    inline sp<IBinder> getApplicationToken() const {
+        return mInfo.token;
+    }
+
+    /**
+     * Requests that the state of this object be updated to reflect
+     * the most current available information about the application.
+     *
+     * This method should only be called from within the input dispatcher's
+     * critical section.
+     *
+     * Returns true on success, or false if the handle is no longer valid.
+     */
+    virtual bool updateInfo() = 0;
+protected:
+    InputApplicationHandle();
+    virtual ~InputApplicationHandle();
+
+    InputApplicationInfo mInfo;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_APPLICATION_H
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1ea69d3..b6efc82 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -19,6 +19,7 @@
 
 #include <input/Input.h>
 #include <input/KeyCharacterMap.h>
+#include <vector>
 
 namespace android {
 
@@ -31,9 +32,9 @@
     }
 
     // Information provided by the kernel.
-    String8 name;
-    String8 location;
-    String8 uniqueId;
+    std::string name;
+    std::string location;
+    std::string uniqueId;
     uint16_t bus;
     uint16_t vendor;
     uint16_t product;
@@ -45,12 +46,21 @@
     // It is hashed from whatever kernel provided information is available.
     // Ideally, the way this value is computed should not change between Android releases
     // because that would invalidate persistent settings that rely on it.
-    String8 descriptor;
+    std::string descriptor;
 
     // A value added to uniquely identify a device in the absence of a unique id. This
     // is intended to be a minimum way to distinguish from other active devices and may
     // reuse values that are not associated with an input anymore.
     uint16_t nonce;
+
+    /**
+     * Return InputDeviceIdentifier.name that has been adjusted as follows:
+     *     - all characters besides alphanumerics, dash,
+     *       and underscore have been replaced with underscores.
+     * This helps in situations where a file that matches the device name is needed,
+     * while conforming to the filename limitations.
+     */
+    std::string getCanonicalName() const;
 };
 
 /*
@@ -73,16 +83,16 @@
     };
 
     void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
-            const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+            const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
             bool hasMic);
 
     inline int32_t getId() const { return mId; }
     inline int32_t getControllerNumber() const { return mControllerNumber; }
     inline int32_t getGeneration() const { return mGeneration; }
     inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; }
-    inline const String8& getAlias() const { return mAlias; }
-    inline const String8& getDisplayName() const {
-        return mAlias.isEmpty() ? mIdentifier.name : mAlias;
+    inline const std::string& getAlias() const { return mAlias; }
+    inline const std::string& getDisplayName() const {
+        return mAlias.empty() ? mIdentifier.name : mAlias;
     }
     inline bool isExternal() const { return mIsExternal; }
     inline bool hasMic() const { return mHasMic; }
@@ -112,7 +122,7 @@
     inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; }
     inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; }
 
-    inline const Vector<MotionRange>& getMotionRanges() const {
+    inline const std::vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
 
@@ -121,7 +131,7 @@
     int32_t mGeneration;
     int32_t mControllerNumber;
     InputDeviceIdentifier mIdentifier;
-    String8 mAlias;
+    std::string mAlias;
     bool mIsExternal;
     bool mHasMic;
     uint32_t mSources;
@@ -130,7 +140,7 @@
     bool mHasVibrator;
     bool mHasButtonUnderPad;
 
-    Vector<MotionRange> mMotionRanges;
+    std::vector<MotionRange> mMotionRanges;
 };
 
 /* Types of input device configuration files. */
@@ -149,7 +159,7 @@
  *
  * Returns an empty string if not found.
  */
-extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+extern std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
         const InputDeviceIdentifier& deviceIdentifier,
         InputDeviceConfigurationFileType type);
 
@@ -162,8 +172,15 @@
  *
  * Returns an empty string if not found.
  */
-extern String8 getInputDeviceConfigurationFilePathByName(
-        const String8& name, InputDeviceConfigurationFileType type);
+extern std::string getInputDeviceConfigurationFilePathByName(
+        const std::string& name, InputDeviceConfigurationFileType type);
+
+enum ReservedInputDeviceId : int32_t {
+    // Device id of a special "virtual" keyboard that is always present.
+    VIRTUAL_KEYBOARD_ID = -1,
+    // Device id of the "built-in" keyboard if there is one.
+    BUILT_IN_KEYBOARD_ID = 0,
+};
 
 } // namespace android
 
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 4b33a96..59d16d1 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -325,8 +325,11 @@
     DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT),
     DEFINE_KEYCODE(ALL_APPS),
     DEFINE_KEYCODE(REFRESH),
+    DEFINE_KEYCODE(THUMBS_UP),
+    DEFINE_KEYCODE(THUMBS_DOWN),
+    DEFINE_KEYCODE(PROFILE_SWITCH),
 
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static const InputEventLabel AXES[] = {
@@ -375,7 +378,7 @@
 
     // NOTE: If you add a new axis here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static const InputEventLabel LEDS[] = {
@@ -396,7 +399,7 @@
     DEFINE_LED(CONTROLLER_4),
 
     // NOTE: If you add new LEDs here, you must also add them to Input.h
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static const InputEventLabel FLAGS[] = {
@@ -404,7 +407,7 @@
     DEFINE_FLAG(FUNCTION),
     DEFINE_FLAG(GESTURE),
 
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {
@@ -424,7 +427,7 @@
         }
         list++;
     }
-    return NULL;
+    return nullptr;
 }
 
 static inline int32_t getKeyCodeByLabel(const char* label) {
@@ -435,7 +438,7 @@
     if (keyCode >= 0 && keyCode < static_cast<int32_t>(size(KEYCODES))) {
         return KEYCODES[keyCode].literal;
     }
-    return NULL;
+    return nullptr;
 }
 
 static inline uint32_t getKeyFlagByLabel(const char* label) {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index ecdc075..63606e5 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -17,6 +17,8 @@
 #ifndef _LIBINPUT_INPUT_TRANSPORT_H
 #define _LIBINPUT_INPUT_TRANSPORT_H
 
+#pragma GCC system_header
+
 /**
  * Native input transport.
  *
@@ -27,6 +29,9 @@
  * The InputConsumer is used by the application to receive events from the input dispatcher.
  */
 
+#include <string>
+
+#include <binder/IBinder.h>
 #include <input/Input.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
@@ -35,6 +40,7 @@
 #include <utils/BitSet.h>
 
 namespace android {
+class Parcel;
 
 /*
  * Intermediate representation used to send input events and related signals.
@@ -99,8 +105,9 @@
             int32_t flags;
             int32_t metaState;
             int32_t buttonState;
+            MotionClassification classification; // base type: uint8_t
+            uint8_t empty2[3];
             int32_t edgeFlags;
-            uint32_t empty2;
             nsecs_t downTime __attribute__((aligned(8)));
             float xOffset;
             float yOffset;
@@ -154,6 +161,7 @@
     virtual ~InputChannel();
 
 public:
+    InputChannel() = default;
     InputChannel(const std::string& name, int fd);
 
     /* Creates a pair of input channels.
@@ -194,9 +202,19 @@
     /* Returns a new object that has a duplicate of this channel's fd. */
     sp<InputChannel> dup() const;
 
+    status_t write(Parcel& out) const;
+    status_t read(const Parcel& from);
+
+    sp<IBinder> getToken() const;
+    void setToken(const sp<IBinder>& token);
+
 private:
+    void setFd(int fd);
+
     std::string mName;
-    int mFd;
+    int mFd = -1;
+
+    sp<IBinder> mToken = nullptr;
 };
 
 /*
@@ -225,6 +243,7 @@
             uint32_t seq,
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t flags,
             int32_t keyCode,
@@ -253,6 +272,7 @@
             int32_t edgeFlags,
             int32_t metaState,
             int32_t buttonState,
+            MotionClassification classification,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -318,7 +338,7 @@
      * Other errors probably indicate that the channel is broken.
      */
     status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
 
     /* Sends a finished signal to the publisher to inform it that the message
      * with the specified sequence number has finished being process and whether
@@ -473,10 +493,9 @@
     Vector<SeqChain> mSeqChains;
 
     status_t consumeBatch(InputEventFactoryInterface* factory,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
     status_t consumeSamples(InputEventFactoryInterface* factory,
-            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
-            int32_t* displayId);
+            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
 
     void updateTouchState(InputMessage& msg);
     void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
new file mode 100644
index 0000000..916af69
--- /dev/null
+++ b/include/input/InputWindow.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2011 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 _UI_INPUT_WINDOW_H
+#define _UI_INPUT_WINDOW_H
+
+#include <input/Input.h>
+#include <input/InputTransport.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include "InputApplication.h"
+
+namespace android {
+class Parcel;
+
+/*
+ * Describes the properties of a window that can receive input.
+ */
+struct InputWindowInfo {
+    InputWindowInfo() = default;
+    InputWindowInfo(const Parcel& from);
+
+    // Window flags from WindowManager.LayoutParams
+    enum {
+        FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001,
+        FLAG_DIM_BEHIND        = 0x00000002,
+        FLAG_BLUR_BEHIND        = 0x00000004,
+        FLAG_NOT_FOCUSABLE      = 0x00000008,
+        FLAG_NOT_TOUCHABLE      = 0x00000010,
+        FLAG_NOT_TOUCH_MODAL    = 0x00000020,
+        FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
+        FLAG_KEEP_SCREEN_ON     = 0x00000080,
+        FLAG_LAYOUT_IN_SCREEN   = 0x00000100,
+        FLAG_LAYOUT_NO_LIMITS   = 0x00000200,
+        FLAG_FULLSCREEN      = 0x00000400,
+        FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800,
+        FLAG_DITHER             = 0x00001000,
+        FLAG_SECURE             = 0x00002000,
+        FLAG_SCALED             = 0x00004000,
+        FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000,
+        FLAG_LAYOUT_INSET_DECOR = 0x00010000,
+        FLAG_ALT_FOCUSABLE_IM = 0x00020000,
+        FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
+        FLAG_SHOW_WHEN_LOCKED = 0x00080000,
+        FLAG_SHOW_WALLPAPER = 0x00100000,
+        FLAG_TURN_SCREEN_ON = 0x00200000,
+        FLAG_DISMISS_KEYGUARD = 0x00400000,
+        FLAG_SPLIT_TOUCH = 0x00800000,
+        FLAG_SLIPPERY = 0x20000000,
+        FLAG_NEEDS_MENU_KEY = 0x40000000,
+    };
+
+    // Window types from WindowManager.LayoutParams
+    enum {
+        FIRST_APPLICATION_WINDOW = 1,
+        TYPE_BASE_APPLICATION   = 1,
+        TYPE_APPLICATION        = 2,
+        TYPE_APPLICATION_STARTING = 3,
+        LAST_APPLICATION_WINDOW = 99,
+        FIRST_SUB_WINDOW        = 1000,
+        TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW,
+        TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1,
+        TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
+        TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
+        TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4,
+        LAST_SUB_WINDOW         = 1999,
+        FIRST_SYSTEM_WINDOW     = 2000,
+        TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW,
+        TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1,
+        TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2,
+        TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3,
+        TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4,
+        TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5,
+        TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6,
+        TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7,
+        TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8,
+        TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9,
+        TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10,
+        TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11,
+        TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
+        TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13,
+        TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14,
+        TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
+        TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16,
+        TYPE_STATUS_BAR_SUB_PANEL  = FIRST_SYSTEM_WINDOW+17,
+        TYPE_POINTER            = FIRST_SYSTEM_WINDOW+18,
+        TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
+        TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
+        TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
+        TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
+        TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
+        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
+        TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
+        TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
+        LAST_SYSTEM_WINDOW      = 2999,
+    };
+
+    enum {
+        INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
+        INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002,
+        INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004,
+    };
+
+    /* These values are filled in by the WM and passed through SurfaceFlinger
+     * unless specified otherwise.
+     */
+    sp<IBinder> token;
+    std::string name;
+    int32_t layoutParamsFlags;
+    int32_t layoutParamsType;
+    nsecs_t dispatchingTimeout;
+
+    /* These values are filled in by SurfaceFlinger. */
+    int32_t frameLeft;
+    int32_t frameTop;
+    int32_t frameRight;
+    int32_t frameBottom;
+
+    /*
+     * SurfaceFlinger consumes this value to shrink the computed frame. This is
+     * different from shrinking the touchable region in that it DOES shift the coordinate
+     * space where-as the touchable region does not and is more like "cropping". This
+     * is used for window shadows.
+     */
+    int32_t surfaceInset = 0;
+
+    // A global scaling factor for all windows. Unlike windowScaleX/Y this results
+    // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis.
+    float globalScaleFactor;
+
+    // Scaling factors applied to individual windows.
+    float windowXScale = 1.0f;
+    float windowYScale = 1.0f;
+
+    /*
+     * This is filled in by the WM relative to the frame and then translated
+     * to absolute coordinates by SurfaceFlinger once the frame is computed.
+     */
+    Region touchableRegion;
+    bool visible;
+    bool canReceiveKeys;
+    bool hasFocus;
+    bool hasWallpaper;
+    bool paused;
+    int32_t layer;
+    int32_t ownerPid;
+    int32_t ownerUid;
+    int32_t inputFeatures;
+    int32_t displayId;
+    int32_t portalToDisplayId = ADISPLAY_ID_NONE;
+    InputApplicationInfo applicationInfo;
+    bool replaceTouchableRegionWithCrop;
+    wp<IBinder> touchableRegionCropHandle;
+
+    void addTouchableRegion(const Rect& region);
+
+    bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
+    bool frameContainsPoint(int32_t x, int32_t y) const;
+
+    /* Returns true if the window is of a trusted type that is allowed to silently
+     * overlay other windows for the purpose of implementing the secure views feature.
+     * Trusted overlays, such as IME windows, can partly obscure other windows without causing
+     * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+     */
+    bool isTrustedOverlay() const;
+
+    bool supportsSplitTouch() const;
+
+    bool overlaps(const InputWindowInfo* other) const;
+
+    status_t write(Parcel& output) const;
+    static InputWindowInfo read(const Parcel& from);
+};
+
+
+/*
+ * Handle for a window that can receive input.
+ *
+ * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * that describe a window.
+ */
+class InputWindowHandle : public RefBase {
+public:
+
+    inline const InputWindowInfo* getInfo() const {
+        return &mInfo;
+    }
+
+    sp<IBinder> getToken() const;
+
+    sp<IBinder> getApplicationToken() {
+        return mInfo.applicationInfo.token;
+    }
+
+    inline std::string getName() const {
+        return mInfo.token ? mInfo.name : "<invalid>";
+    }
+
+    inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
+        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
+    }
+
+    /**
+     * Requests that the state of this object be updated to reflect
+     * the most current available information about the application.
+     *
+     * This method should only be called from within the input dispatcher's
+     * critical section.
+     *
+     * Returns true on success, or false if the handle is no longer valid.
+     */
+    virtual bool updateInfo() = 0;
+
+    /**
+     * Updates from another input window handle.
+     */
+    void updateFrom(const sp<InputWindowHandle> handle);
+
+    /**
+     * Releases the channel used by the associated information when it is
+     * no longer needed.
+     */
+    void releaseChannel();
+
+protected:
+    explicit InputWindowHandle();
+    virtual ~InputWindowHandle();
+
+    InputWindowInfo mInfo;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_WINDOW_H
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 33d2757..a1a32a6 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -27,7 +27,6 @@
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
-#include <utils/String8.h>
 #include <utils/Unicode.h>
 #include <utils/RefBase.h>
 
@@ -75,10 +74,10 @@
     };
 
     /* Loads a key character map from a file. */
-    static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
+    static status_t load(const std::string& filename, Format format, sp<KeyCharacterMap>* outMap);
 
     /* Loads a key character map from its string contents. */
-    static status_t loadContents(const String8& filename,
+    static status_t loadContents(const std::string& filename,
             const char* contents, Format format, sp<KeyCharacterMap>* outMap);
 
     /* Combines a base key character map and an overlay. */
@@ -196,7 +195,7 @@
         };
 
         struct Property {
-            inline Property(int32_t property = 0, int32_t metaState = 0) :
+            inline explicit Property(int32_t property = 0, int32_t metaState = 0) :
                     property(property), metaState(metaState) { }
 
             int32_t property;
@@ -221,7 +220,7 @@
         status_t parseKey();
         status_t parseKeyProperty();
         status_t finishKey(Key* key);
-        status_t parseModifier(const String8& token, int32_t* outMetaState);
+        status_t parseModifier(const std::string& token, int32_t* outMetaState);
         status_t parseCharacterLiteral(char16_t* outCharacter);
     };
 
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 1e8de71..26f3501 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -62,11 +62,11 @@
  */
 class KeyLayoutMap : public RefBase {
 public:
-    static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap);
+    static status_t load(const std::string& filename, sp<KeyLayoutMap>* outMap);
 
     status_t mapKey(int32_t scanCode, int32_t usageCode,
             int32_t* outKeyCode, uint32_t* outFlags) const;
-    status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
+    status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
     status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
     status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
 
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index d4903e9..92da10c 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -21,20 +21,10 @@
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
 #include <utils/Errors.h>
-#include <utils/String8.h>
 #include <utils/PropertyMap.h>
 
 namespace android {
 
-enum {
-    /* Device id of the built in keyboard. */
-    DEVICE_ID_BUILT_IN_KEYBOARD = 0,
-
-    /* Device id of a generic virtual keyboard with a full layout that can be used
-     * to synthesize key events. */
-    DEVICE_ID_VIRTUAL_KEYBOARD = -1,
-};
-
 class KeyLayoutMap;
 class KeyCharacterMap;
 
@@ -43,10 +33,10 @@
  */
 class KeyMap {
 public:
-    String8 keyLayoutFile;
+    std::string keyLayoutFile;
     sp<KeyLayoutMap> keyLayoutMap;
 
-    String8 keyCharacterMapFile;
+    std::string keyCharacterMapFile;
     sp<KeyCharacterMap> keyCharacterMap;
 
     KeyMap();
@@ -56,11 +46,11 @@
             const PropertyMap* deviceConfiguration);
 
     inline bool haveKeyLayout() const {
-        return !keyLayoutFile.isEmpty();
+        return !keyLayoutFile.empty();
     }
 
     inline bool haveKeyCharacterMap() const {
-        return !keyCharacterMapFile.isEmpty();
+        return !keyCharacterMapFile.empty();
     }
 
     inline bool isComplete() const {
@@ -68,12 +58,12 @@
     }
 
 private:
-    bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
-    status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
+    bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
+    status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const std::string& name);
     status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-            const String8& name);
-    String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
-            const String8& name, InputDeviceConfigurationFileType type);
+            const std::string& name);
+    std::string getPath(const InputDeviceIdentifier& deviceIdentifier,
+            const std::string& name, InputDeviceConfigurationFileType type);
 };
 
 /**
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
new file mode 100644
index 0000000..b49c623
--- /dev/null
+++ b/include/input/TouchVideoFrame.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBINPUT_TOUCHVIDEOFRAME_H
+#define _LIBINPUT_TOUCHVIDEOFRAME_H
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <ui/DisplayInfo.h>
+#include <vector>
+
+namespace android {
+
+/**
+ * Represents data from a single scan of the touchscreen device.
+ * Similar in concept to a video frame, but the touch strength is used as
+ * the values instead.
+ */
+class TouchVideoFrame {
+public:
+    TouchVideoFrame(uint32_t height, uint32_t width, std::vector<int16_t> data,
+            const struct timeval& timestamp);
+
+    bool operator==(const TouchVideoFrame& rhs) const;
+
+    /**
+     * Height of the frame
+     */
+    uint32_t getHeight() const;
+    /**
+     * Width of the frame
+     */
+    uint32_t getWidth() const;
+    /**
+     * The touch strength data.
+     * The array is a 2-D row-major matrix, with dimensions (height, width).
+     * Total size of the array should equal getHeight() * getWidth().
+     * Data is allowed to be negative.
+     */
+    const std::vector<int16_t>& getData() const;
+    /**
+     * Time at which the heatmap was taken.
+     */
+    const struct timeval& getTimestamp() const;
+
+    /**
+     * Rotate the video frame.
+     * The rotation value is an enum from ui/DisplayInfo.h
+     */
+    void rotate(int32_t orientation);
+
+private:
+    uint32_t mHeight;
+    uint32_t mWidth;
+    std::vector<int16_t> mData;
+    struct timeval mTimestamp;
+
+    /**
+     * Common method for 90 degree and 270 degree rotation
+     */
+    void rotateQuarterTurn(bool clockwise);
+    void rotate180();
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_TOUCHVIDEOFRAME_H
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index ffa1614..727865a 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -63,7 +63,7 @@
 
     // Creates a velocity tracker using the specified strategy.
     // If strategy is NULL, uses the default strategy for the platform.
-    VelocityTracker(const char* strategy = NULL);
+    VelocityTracker(const char* strategy = nullptr);
 
     ~VelocityTracker();
 
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index e245ead..6e8e2c9 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -23,8 +23,8 @@
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
-#include <utils/String8.h>
 #include <utils/Unicode.h>
+#include <vector>
 
 namespace android {
 
@@ -50,9 +50,9 @@
 public:
     ~VirtualKeyMap();
 
-    static status_t load(const String8& filename, VirtualKeyMap** outMap);
+    static std::unique_ptr<VirtualKeyMap> load(const std::string& filename);
 
-    inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
+    inline const std::vector<VirtualKeyDefinition>& getVirtualKeys() const {
         return mVirtualKeys;
     }
 
@@ -71,7 +71,7 @@
         bool parseNextIntField(int32_t* outValue);
     };
 
-    Vector<VirtualKeyDefinition> mVirtualKeys;
+    std::vector<VirtualKeyDefinition> mVirtualKeys;
 
     VirtualKeyMap();
 };
diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h
index 3c81f0f..853f0c9 100644
--- a/include/powermanager/IPowerManager.h
+++ b/include/powermanager/IPowerManager.h
@@ -45,7 +45,7 @@
         IS_INTERACTIVE               = IBinder::FIRST_CALL_TRANSACTION + 11,
         IS_POWER_SAVE_MODE           = IBinder::FIRST_CALL_TRANSACTION + 12,
         GET_POWER_SAVE_STATE         = IBinder::FIRST_CALL_TRANSACTION + 13,
-        SET_POWER_SAVE_MODE          = IBinder::FIRST_CALL_TRANSACTION + 14,
+        SET_POWER_SAVE_MODE_ENABLED  = IBinder::FIRST_CALL_TRANSACTION + 14,
         REBOOT                       = IBinder::FIRST_CALL_TRANSACTION + 17,
         REBOOT_SAFE_MODE             = IBinder::FIRST_CALL_TRANSACTION + 18,
         SHUTDOWN                     = IBinder::FIRST_CALL_TRANSACTION + 19,
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
new file mode 100644
index 0000000..9284acb
--- /dev/null
+++ b/libs/android_runtime_lazy/Android.bp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// libandroid_runtime_lazy is a shim library.
+// This provides very limited small set of APIs from libandroid_runtime.
+//
+// By depending on this instead of libandroid_runtime,
+// a library can be loaded without paying the cost of libandroid_runtime
+// which is quite huge. The cost will be paid when libandroid_runtime is actually used.
+//
+// For Partial-source PDK build, there is a constraint that
+// frameworks/native modules should not depend on frameworks/base.
+// This library can be used to cut down the dependency between them.
+// (e.g. libbinder_ndk)
+//
+// Some libraries which serve as LL-NDK and NDK as well may depend on this
+// instead of libandroid_runtime. When they are used by a vendor process,
+// depending on libandroid_runtime is meaningless. In this case,
+// they can depend on libandroid_runtime_lazy.
+cc_library {
+    name: "libandroid_runtime_lazy",
+    vendor_available: true,
+    double_loadable: true,
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+    srcs: [
+        "android_runtime_lazy.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+    ],
+
+    required: [
+        "libandroid_runtime",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    header_libs: [
+        "jni_headers",
+        "libbinder_headers",
+    ],
+}
diff --git a/libs/android_runtime_lazy/android_runtime_lazy.cpp b/libs/android_runtime_lazy/android_runtime_lazy.cpp
new file mode 100644
index 0000000..98d8e8a
--- /dev/null
+++ b/libs/android_runtime_lazy/android_runtime_lazy.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "ANDROID_RUNTIME_LAZY"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
+
+#include <dlfcn.h>
+#include <mutex>
+
+#include <log/log.h>
+
+namespace android {
+namespace {
+
+std::once_flag loadFlag;
+
+typedef JNIEnv* (*getJNIEnv_t)();
+typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
+typedef jobject (*javaObjectForIBinder_t)(JNIEnv* env, const sp<IBinder>& val);
+
+getJNIEnv_t _getJNIEnv;
+ibinderForJavaObject_t _ibinderForJavaObject;
+javaObjectForIBinder_t _javaObjectForIBinder;
+
+void load() {
+    std::call_once(loadFlag, []() {
+        void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+        if (handle == nullptr) {
+            ALOGE("Could not open libandroid_runtime.");
+            return;
+        }
+
+        _getJNIEnv = reinterpret_cast<getJNIEnv_t>(
+                dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"));
+        if (_getJNIEnv == nullptr) {
+            ALOGW("Could not find getJNIEnv.");
+            // no return
+        }
+
+        _ibinderForJavaObject = reinterpret_cast<ibinderForJavaObject_t>(
+                dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+        if (_ibinderForJavaObject == nullptr) {
+            ALOGW("Could not find ibinderForJavaObject.");
+            // no return
+        }
+
+        _javaObjectForIBinder = reinterpret_cast<javaObjectForIBinder_t>(
+                dlsym(handle,
+                      "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
+        if (_javaObjectForIBinder == nullptr) {
+            ALOGW("Could not find javaObjectForIBinder.");
+            // no return
+        }
+    });
+}
+
+} // namespace
+
+// exports delegate functions
+
+JNIEnv* AndroidRuntime::getJNIEnv() {
+    load();
+    if (_getJNIEnv == nullptr) {
+        return nullptr;
+    }
+    return _getJNIEnv();
+}
+
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) {
+    load();
+    if (_ibinderForJavaObject == nullptr) {
+        return nullptr;
+    }
+    return _ibinderForJavaObject(env, obj);
+}
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {
+    load();
+    if (_javaObjectForIBinder == nullptr) {
+        return nullptr;
+    }
+    return _javaObjectForIBinder(env, val);
+}
+
+} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h b/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h
new file mode 100644
index 0000000..85231fa
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "jni.h"
+
+namespace android {
+
+// Intentionally use the same name with AndroidRuntime in frameworks/base/core/jni/
+// to make the client use this in the same way with the original class.
+class AndroidRuntime {
+public:
+    static JNIEnv* getJNIEnv();
+};
+
+} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_util_Binder.h b/libs/android_runtime_lazy/include/android_util_Binder.h
new file mode 100644
index 0000000..e47390e
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_util_Binder.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include "jni.h"
+
+namespace android {
+
+// The name of this file is same with the file in frameworks/base/core/jni/
+// This is intentional to make the client use these exported functions
+// in the same way with the original.
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
+
+} // namespace android
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index a20154f..ad8287c 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -25,4 +25,9 @@
     host_supported: true,
     vendor_available: true,
     export_include_dirs: ["include"],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
 }
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 2728f35..49a9414 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -34,16 +34,16 @@
     std::lock_guard<Mutex> scoped_lock(mLock);
     int64_t startTime = 0;
     sp<IActivityManager> service = mService;
-    while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
+    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
         sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity"));
-        if (binder == NULL) {
+        if (binder == nullptr) {
             // Wait for the activity service to come back...
             if (startTime == 0) {
                 startTime = uptimeMillis();
                 ALOGI("Waiting for activity service");
             } else if ((uptimeMillis() - startTime) > 1000000) {
                 ALOGW("Waiting too long for activity service, giving up");
-                service = NULL;
+                service = nullptr;
                 break;
             }
             usleep(25000);
@@ -58,7 +58,7 @@
 int ActivityManager::openContentUri(const String16& stringUri)
 {
     sp<IActivityManager> service = getService();
-    return service != NULL ? service->openContentUri(stringUri) : -1;
+    return service != nullptr ? service->openContentUri(stringUri) : -1;
 }
 
 void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
@@ -67,7 +67,7 @@
                                           const String16& callingPackage)
 {
     sp<IActivityManager> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         service->registerUidObserver(observer, event, cutpoint, callingPackage);
     }
 }
@@ -75,7 +75,7 @@
 void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
 {
     sp<IActivityManager> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         service->unregisterUidObserver(observer);
     }
 }
@@ -83,15 +83,24 @@
 bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage)
 {
     sp<IActivityManager> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         return service->isUidActive(uid, callingPackage);
     }
     return false;
 }
 
+int32_t ActivityManager::getUidProcessState(const uid_t uid, const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != nullptr) {
+        return service->getUidProcessState(uid, callingPackage);
+    }
+    return PROCESS_STATE_UNKNOWN;
+}
+
 status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
     sp<IActivityManager> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         return IInterface::asBinder(service)->linkToDeath(recipient);
     }
     return INVALID_OPERATION;
@@ -99,7 +108,7 @@
 
 status_t ActivityManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
     sp<IActivityManager> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         return IInterface::asBinder(service)->unlinkToDeath(recipient);
     }
     return INVALID_OPERATION;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7c1eaaf..aedf6b0 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -28,7 +28,7 @@
     ],
 }
 
-cc_library {
+cc_library_shared {
     name: "libbinder",
 
     // for vndbinder
@@ -36,6 +36,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
 
     srcs: [
         "ActivityManager.cpp",
@@ -62,6 +63,7 @@
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
         "Parcel.cpp",
+        "ParcelFileDescriptor.cpp",
         "PermissionCache.cpp",
         "PermissionController.cpp",
         "PersistableBundle.cpp",
@@ -105,6 +107,7 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-Wzero-as-null-pointer-constant",
     ],
     product_variables: {
         binder32bit: {
@@ -117,7 +120,7 @@
         "liblog",
         "libcutils",
         "libutils",
-        "libutilscallstack",
+        "libbinderthreadstate",
     ],
 
     header_libs: [
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 62c8987..525685c 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -42,7 +42,7 @@
 
 static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
     pthread_mutex_lock(&gTokenMutex);
-    if (gToken == NULL || gToken->pingBinder() != NO_ERROR) {
+    if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) {
         gToken = service->getToken(new BBinder());
     }
     pthread_mutex_unlock(&gTokenMutex);
@@ -63,16 +63,16 @@
     std::lock_guard<Mutex> scoped_lock(mLock);
     int64_t startTime = 0;
     sp<IAppOpsService> service = mService;
-    while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
+    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
         sp<IBinder> binder = defaultServiceManager()->checkService(_appops);
-        if (binder == NULL) {
+        if (binder == nullptr) {
             // Wait for the app ops service to come back...
             if (startTime == 0) {
                 startTime = uptimeMillis();
                 ALOGI("Waiting for app ops service");
             } else if ((uptimeMillis()-startTime) > 10000) {
                 ALOGW("Waiting too long for app ops service, giving up");
-                service = NULL;
+                service = nullptr;
                 break;
             }
             sleep(1);
@@ -88,14 +88,22 @@
 int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
 {
     sp<IAppOpsService> service = getService();
-    return service != NULL
+    return service != nullptr
             ? service->checkOperation(op, uid, callingPackage)
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
+int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
+        const String16& callingPackage) {
+    sp<IAppOpsService> service = getService();
+    return service != nullptr
+           ? service->checkAudioOperation(op, usage, uid, callingPackage)
+           : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+}
+
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
     sp<IAppOpsService> service = getService();
-    return service != NULL
+    return service != nullptr
             ? service->noteOperation(op, uid, callingPackage)
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
@@ -103,14 +111,14 @@
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
         bool startIfModeDefault) {
     sp<IAppOpsService> service = getService();
-    return service != NULL
+    return service != nullptr
             ? service->startOperation(getToken(service), op, uid, callingPackage,
                     startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
     sp<IAppOpsService> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         service->finishOperation(getToken(service), op, uid, callingPackage);
     }
 }
@@ -118,21 +126,21 @@
 void AppOpsManager::startWatchingMode(int32_t op, const String16& packageName,
         const sp<IAppOpsCallback>& callback) {
     sp<IAppOpsService> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         service->startWatchingMode(op, packageName, callback);
     }
 }
 
 void AppOpsManager::stopWatchingMode(const sp<IAppOpsCallback>& callback) {
     sp<IAppOpsService> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         service->stopWatchingMode(callback);
     }
 }
 
 int32_t AppOpsManager::permissionToOpCode(const String16& permission) {
     sp<IAppOpsService> service = getService();
-    if (service != NULL) {
+    if (service != nullptr) {
         return service->permissionToOpCode(permission);
     }
     return -1;
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index a81f44e..cb0e08d 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -43,17 +43,17 @@
 
 sp<IInterface>  IBinder::queryLocalInterface(const String16& /*descriptor*/)
 {
-    return NULL;
+    return nullptr;
 }
 
 BBinder* IBinder::localBinder()
 {
-    return NULL;
+    return nullptr;
 }
 
 BpBinder* IBinder::remoteBinder()
 {
-    return NULL;
+    return nullptr;
 }
 
 bool IBinder::checkSubclass(const void* /*subclassID*/) const
@@ -76,8 +76,8 @@
     for (size_t i = 0; i < numArgs; i++) {
         send.writeString16(args[i]);
     }
-    send.writeStrongBinder(callback != NULL ? IInterface::asBinder(callback) : NULL);
-    send.writeStrongBinder(resultReceiver != NULL ? IInterface::asBinder(resultReceiver) : NULL);
+    send.writeStrongBinder(callback != nullptr ? IInterface::asBinder(callback) : nullptr);
+    send.writeStrongBinder(resultReceiver != nullptr ? IInterface::asBinder(resultReceiver) : nullptr);
     return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
 }
 
@@ -86,6 +86,10 @@
 class BBinder::Extras
 {
 public:
+    // unlocked objects
+    bool mRequestingSid = false;
+
+    // for below objects
     Mutex mLock;
     BpBinder::ObjectManager mObjects;
 };
@@ -115,6 +119,7 @@
     return sEmptyDescriptor;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::transact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -130,13 +135,14 @@
             break;
     }
 
-    if (reply != NULL) {
+    if (reply != nullptr) {
         reply->setDataPosition(0);
     }
 
     return err;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::linkToDeath(
     const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
     uint32_t /*flags*/)
@@ -144,6 +150,7 @@
     return INVALID_OPERATION;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::unlinkToDeath(
     const wp<DeathRecipient>& /*recipient*/, void* /*cookie*/,
     uint32_t /*flags*/, wp<DeathRecipient>* /*outRecipient*/)
@@ -160,19 +167,8 @@
     const void* objectID, void* object, void* cleanupCookie,
     object_cleanup_func func)
 {
-    Extras* e = mExtras.load(std::memory_order_acquire);
-
-    if (!e) {
-        e = new Extras;
-        Extras* expected = nullptr;
-        if (!mExtras.compare_exchange_strong(expected, e,
-                                             std::memory_order_release,
-                                             std::memory_order_acquire)) {
-            delete e;
-            e = expected;  // Filled in by CAS
-        }
-        if (e == 0) return; // out of memory
-    }
+    Extras* e = getOrCreateExtras();
+    if (!e) return; // out of memory
 
     AutoMutex _l(e->mLock);
     e->mObjects.attach(objectID, object, cleanupCookie, func);
@@ -181,7 +177,7 @@
 void* BBinder::findObject(const void* objectID) const
 {
     Extras* e = mExtras.load(std::memory_order_acquire);
-    if (!e) return NULL;
+    if (!e) return nullptr;
 
     AutoMutex _l(e->mLock);
     return e->mObjects.find(objectID);
@@ -201,6 +197,30 @@
     return this;
 }
 
+bool BBinder::isRequestingSid()
+{
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    return e && e->mRequestingSid;
+}
+
+void BBinder::setRequestingSid(bool requestingSid)
+{
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    if (!e) {
+        // default is false. Most things don't need sids, so avoiding allocations when possible.
+        if (!requestingSid) {
+            return;
+        }
+
+        e = getOrCreateExtras();
+        if (!e) return; // out of memory
+    }
+
+    e->mRequestingSid = requestingSid;
+}
+
 BBinder::~BBinder()
 {
     Extras* e = mExtras.load(std::memory_order_relaxed);
@@ -208,6 +228,7 @@
 }
 
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BBinder::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
 {
@@ -246,7 +267,7 @@
             (void)out;
             (void)err;
 
-            if (resultReceiver != NULL) {
+            if (resultReceiver != nullptr) {
                 resultReceiver->send(INVALID_OPERATION);
             }
 
@@ -263,6 +284,25 @@
     }
 }
 
+BBinder::Extras* BBinder::getOrCreateExtras()
+{
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    if (!e) {
+        e = new Extras;
+        Extras* expected = nullptr;
+        if (!mExtras.compare_exchange_strong(expected, e,
+                                             std::memory_order_release,
+                                             std::memory_order_acquire)) {
+            delete e;
+            e = expected;  // Filled in by CAS
+        }
+        if (e == nullptr) return nullptr; // out of memory
+    }
+
+    return e;
+}
+
 // ---------------------------------------------------------------------------
 
 enum {
@@ -273,7 +313,7 @@
 };
 
 BpRefBase::BpRefBase(const sp<IBinder>& o)
-    : mRemote(o.get()), mRefs(NULL), mState(0)
+    : mRemote(o.get()), mRefs(nullptr), mState(0)
 {
     extendObjectLifetime(OBJECT_LIFETIME_WEAK);
 
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 449a9e9..ec170f7 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -80,7 +80,7 @@
 void* BpBinder::ObjectManager::find(const void* objectID) const
 {
     const ssize_t i = mObjects.indexOfKey(objectID);
-    if (i < 0) return NULL;
+    if (i < 0) return nullptr;
     return mObjects.valueAt(i).object;
 }
 
@@ -95,7 +95,7 @@
     ALOGV("Killing %zu objects in manager %p", N, this);
     for (size_t i=0; i<N; i++) {
         const entry_t& e = mObjects.valueAt(i);
-        if (e.func != NULL) {
+        if (e.func != nullptr) {
             e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
         }
     }
@@ -139,7 +139,7 @@
     : mHandle(handle)
     , mAlive(1)
     , mObitsSent(0)
-    , mObituaries(NULL)
+    , mObituaries(nullptr)
     , mTrackedUid(trackedUid)
 {
     ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
@@ -206,6 +206,7 @@
     return err;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::transact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -220,6 +221,7 @@
     return DEAD_OBJECT;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::linkToDeath(
     const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
 {
@@ -228,7 +230,7 @@
     ob.cookie = cookie;
     ob.flags = flags;
 
-    LOG_ALWAYS_FATAL_IF(recipient == NULL,
+    LOG_ALWAYS_FATAL_IF(recipient == nullptr,
                         "linkToDeath(): recipient must be non-NULL");
 
     {
@@ -254,6 +256,7 @@
     return DEAD_OBJECT;
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BpBinder::unlinkToDeath(
     const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
     wp<DeathRecipient>* outRecipient)
@@ -268,9 +271,9 @@
     for (size_t i=0; i<N; i++) {
         const Obituary& obit = mObituaries->itemAt(i);
         if ((obit.recipient == recipient
-                    || (recipient == NULL && obit.cookie == cookie))
+                    || (recipient == nullptr && obit.cookie == cookie))
                 && obit.flags == flags) {
-            if (outRecipient != NULL) {
+            if (outRecipient != nullptr) {
                 *outRecipient = mObituaries->itemAt(i).recipient;
             }
             mObituaries->removeAt(i);
@@ -280,7 +283,7 @@
                 self->clearDeathNotification(mHandle, this);
                 self->flushCommands();
                 delete mObituaries;
-                mObituaries = NULL;
+                mObituaries = nullptr;
             }
             return NO_ERROR;
         }
@@ -299,12 +302,12 @@
 
     mLock.lock();
     Vector<Obituary>* obits = mObituaries;
-    if(obits != NULL) {
+    if(obits != nullptr) {
         ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
         IPCThreadState* self = IPCThreadState::self();
         self->clearDeathNotification(mHandle, this);
         self->flushCommands();
-        mObituaries = NULL;
+        mObituaries = nullptr;
     }
     mObitsSent = 1;
     mLock.unlock();
@@ -312,7 +315,7 @@
     ALOGV("Reporting death of proxy %p for %zu recipients\n",
         this, obits ? obits->size() : 0U);
 
-    if (obits != NULL) {
+    if (obits != nullptr) {
         const size_t N = obits->size();
         for (size_t i=0; i<N; i++) {
             reportOneDeath(obits->itemAt(i));
@@ -326,7 +329,7 @@
 {
     sp<DeathRecipient> recipient = obit.recipient.promote();
     ALOGV("Reporting death to recipient: %p\n", recipient.get());
-    if (recipient == NULL) return;
+    if (recipient == nullptr) return;
 
     recipient->binderDied(this);
 }
@@ -386,13 +389,13 @@
 
     mLock.lock();
     Vector<Obituary>* obits = mObituaries;
-    if(obits != NULL) {
+    if(obits != nullptr) {
         if (ipc) ipc->clearDeathNotification(mHandle, this);
-        mObituaries = NULL;
+        mObituaries = nullptr;
     }
     mLock.unlock();
 
-    if (obits != NULL) {
+    if (obits != nullptr) {
         // XXX Should we tell any remaining DeathRecipient
         // objects that the last strong ref has gone away, so they
         // are no longer linked?
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 30e70b0..857bbf9 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -25,6 +25,7 @@
 
 #include <private/binder/Static.h>
 
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -36,7 +37,7 @@
 {
     explicit BufferState(int32_t _seq)
         : seq(_seq)
-        , buffer(NULL)
+        , buffer(nullptr)
         , bufferPos(0)
         , bufferSize(0)
         , atFront(true)
@@ -87,7 +88,7 @@
     Vector<sp<BufferedTextOutput::BufferState> > states;
 };
 
-static mutex_t          gMutex;
+static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
 
 static thread_store_t   tls;
 
@@ -113,7 +114,7 @@
 {
     int32_t res = -1;
     
-    mutex_lock(&gMutex);
+    pthread_mutex_lock(&gMutex);
     
     if (gFreeBufferIndex >= 0) {
         res = gFreeBufferIndex;
@@ -125,17 +126,17 @@
         gTextBuffers.add(-1);
     }
 
-    mutex_unlock(&gMutex);
+    pthread_mutex_unlock(&gMutex);
     
     return res;
 }
 
 static void freeBufferIndex(int32_t idx)
 {
-    mutex_lock(&gMutex);
+    pthread_mutex_lock(&gMutex);
     gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
     gFreeBufferIndex = idx;
-    mutex_unlock(&gMutex);
+    pthread_mutex_unlock(&gMutex);
 }
 
 // ---------------------------------------------------------------------------
@@ -188,7 +189,7 @@
                 // them out without going through the buffer.
                 
                 // Slurp up all of the lines.
-                const char* lastLine = txt+1;
+                const char* lastLine = txt;
                 while (txt < end) {
                     if (*txt++ == '\n') lastLine = txt;
                 }
@@ -266,13 +267,13 @@
     if ((mFlags&MULTITHREADED) != 0) {
         ThreadState* ts = getThreadState();
         if (ts) {
-            while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL);
+            while (ts->states.size() <= (size_t)mIndex) ts->states.add(nullptr);
             BufferState* bs = ts->states[mIndex].get();
-            if (bs != NULL && bs->seq == mSeq) return bs;
+            if (bs != nullptr && bs->seq == mSeq) return bs;
             
             ts->states.editItemAt(mIndex) = new BufferState(mIndex);
             bs = ts->states[mIndex].get();
-            if (bs != NULL) return bs;
+            if (bs != nullptr) return bs;
         }
     }
     
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index 4ac61a3..a1c2a8b 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -165,13 +165,13 @@
         else if (bytesPerLine >= 8) alignment = 2;
         else alignment = 1;
     }
-    if (func == NULL) func = defaultPrintFunc;
+    if (func == nullptr) func = defaultPrintFunc;
 
     size_t offset;
 
     unsigned char *pos = (unsigned char *)buf;
 
-    if (pos == NULL) {
+    if (pos == nullptr) {
         if (singleLineBytesCutoff < 0) func(cookie, "\n");
         func(cookie, "(NULL)");
         return;
@@ -221,7 +221,11 @@
 
         for (word = 0; word < bytesPerLine; ) {
 
-            const size_t startIndex = word+(alignment-(alignment?1:0));
+            size_t align_offset = alignment-(alignment?1:0);
+            if (remain > 0 && (size_t)remain <= align_offset) {
+                align_offset = remain - 1;
+            }
+            const size_t startIndex = word+align_offset;
 
             for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
 
@@ -297,7 +301,7 @@
 
 ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf) {
     sp<ProcessState> proc = ProcessState::selfOrNull();
-    if (proc.get() == NULL) {
+    if (proc.get() == nullptr) {
         return 0;
     }
 
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 428db4d..377f604 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -17,8 +17,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include <binder/ActivityManager.h>
 #include <binder/IActivityManager.h>
-
 #include <binder/Parcel.h>
 
 namespace android {
@@ -90,6 +90,20 @@
          if (reply.readExceptionCode() != 0) return false;
          return reply.readInt32() == 1;
     }
+
+    virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        data.writeString16(callingPackage);
+        remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) {
+            return ActivityManager::PROCESS_STATE_UNKNOWN;
+        }
+        return reply.readInt32();
+    }
 };
 
 // ------------------------------------------------------------------------------------
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index f9ec593..aba4967 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -49,6 +49,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnAppOpsCallback::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -56,7 +57,8 @@
         case OP_CHANGED_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsCallback, data, reply);
             int32_t op = data.readInt32();
-            String16 packageName = data.readString16();
+            String16 packageName;
+            (void)data.readString16(&packageName);
             opChanged(op, packageName);
             reply->writeNoException();
             return NO_ERROR;
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 9c76350..66d6e31 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -109,7 +109,7 @@
         data.writeStrongBinder(clientToken);
         remote()->transact(GET_TOKEN_TRANSACTION, data, &reply);
         // fail on exception
-        if (reply.readExceptionCode() != 0) return NULL;
+        if (reply.readExceptionCode() != 0) return nullptr;
         return reply.readStrongBinder();
     }
 
@@ -123,12 +123,29 @@
         if (reply.readExceptionCode() != 0) return -1;
         return reply.readInt32();
     }
+
+    virtual int32_t checkAudioOperation(int32_t code, int32_t usage,
+            int32_t uid, const String16& packageName) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+        data.writeInt32(code);
+        data.writeInt32(usage);
+        data.writeInt32(uid);
+        data.writeString16(packageName);
+        remote()->transact(CHECK_AUDIO_OPERATION_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) {
+            return MODE_ERRORED;
+        }
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnAppOpsService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -208,6 +225,17 @@
             reply->writeInt32(opCode);
             return NO_ERROR;
         } break;
+        case CHECK_AUDIO_OPERATION_TRANSACTION: {
+            CHECK_INTERFACE(IAppOpsService, data, reply);
+            const int32_t code = data.readInt32();
+            const int32_t usage = data.readInt32();
+            const int32_t uid = data.readInt32();
+            const String16 packageName = data.readString16();
+            const int32_t res = checkAudioOperation(code, usage, uid, packageName);
+            reply->writeNoException();
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index ad1e69f..b307e3e 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -136,6 +136,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnBatteryStats::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
index 2fcd3d9..59d51ed 100644
--- a/libs/binder/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -32,14 +32,14 @@
 // static
 sp<IBinder> IInterface::asBinder(const IInterface* iface)
 {
-    if (iface == NULL) return NULL;
+    if (iface == nullptr) return nullptr;
     return const_cast<IInterface*>(iface)->onAsBinder();
 }
 
 // static
 sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
 {
-    if (iface == NULL) return NULL;
+    if (iface == nullptr) return nullptr;
     return iface->onAsBinder();
 }
 
@@ -47,21 +47,3 @@
 // ---------------------------------------------------------------------------
 
 }; // namespace android
-
-extern "C" {
-
-void _ZN7android10IInterface8asBinderEv(void *retval, void* self) {
-    ALOGW("deprecated asBinder call, please update your code");
-    //ALOGI("self: %p, retval: %p", self, retval);
-    android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>;
-    *ret = android::IInterface::asBinder((android::IInterface*)self);
-}
-
-void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) {
-    ALOGW("deprecated asBinder call, please update your code");
-    //ALOGI("self: %p, retval: %p", self, retval);
-    android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>;
-    *ret = android::IInterface::asBinder((android::IInterface*)self);
-}
-
-} // extern "C"
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 5c1a4f4..caf2318 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -31,7 +31,6 @@
 #include <binder/Parcel.h>
 #include <log/log.h>
 
-#include <utils/CallStack.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 
@@ -87,7 +86,7 @@
     virtual void* getBase() const;
     virtual size_t getSize() const;
     virtual uint32_t getFlags() const;
-    virtual uint32_t getOffset() const;
+    off_t getOffset() const override;
 
 private:
     friend class IMemory;
@@ -114,7 +113,7 @@
     mutable void*       mBase;
     mutable size_t      mSize;
     mutable uint32_t    mFlags;
-    mutable uint32_t    mOffset;
+    mutable off_t       mOffset;
     mutable bool        mRealHeap;
     mutable Mutex       mLock;
 };
@@ -130,7 +129,8 @@
 public:
     explicit BpMemory(const sp<IBinder>& impl);
     virtual ~BpMemory();
-    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
+    // NOLINTNEXTLINE(google-default-arguments)
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const;
 
 private:
     mutable sp<IMemoryHeap> mHeap;
@@ -145,22 +145,22 @@
     sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
     void* const base = realHeap->base();
     if (base == MAP_FAILED)
-        return 0;
+        return nullptr;
     return static_cast<char*>(base) + offset;
 }
 
 void* IMemory::pointer() const {
     ssize_t offset;
     sp<IMemoryHeap> heap = getMemory(&offset);
-    void* const base = heap!=0 ? heap->base() : MAP_FAILED;
+    void* const base = heap!=nullptr ? heap->base() : MAP_FAILED;
     if (base == MAP_FAILED)
-        return 0;
+        return nullptr;
     return static_cast<char*>(base) + offset;
 }
 
 size_t IMemory::size() const {
     size_t size;
-    getMemory(NULL, &size);
+    getMemory(nullptr, &size);
     return size;
 }
 
@@ -181,20 +181,24 @@
 {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
 {
-    if (mHeap == 0) {
+    if (mHeap == nullptr) {
         Parcel data, reply;
         data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
         if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
             sp<IBinder> heap = reply.readStrongBinder();
-            ssize_t o = reply.readInt32();
-            size_t s = reply.readInt32();
-            if (heap != 0) {
+            if (heap != nullptr) {
                 mHeap = interface_cast<IMemoryHeap>(heap);
-                if (mHeap != 0) {
+                if (mHeap != nullptr) {
+                    const int64_t offset64 = reply.readInt64();
+                    const uint64_t size64 = reply.readUint64();
+                    const ssize_t o = (ssize_t)offset64;
+                    const size_t s = (size_t)size64;
                     size_t heapSize = mHeap->getSize();
-                    if (s <= heapSize
+                    if (s == size64 && o == offset64 // ILP32 bounds check
+                            && s <= heapSize
                             && o >= 0
                             && (static_cast<size_t>(o) <= heapSize - s)) {
                         mOffset = o;
@@ -202,7 +206,7 @@
                     } else {
                         // Hm.
                         android_errorWriteWithInfoLog(0x534e4554,
-                            "26877992", -1, NULL, 0);
+                            "26877992", -1, nullptr, 0);
                         mOffset = 0;
                         mSize = 0;
                     }
@@ -212,7 +216,7 @@
     }
     if (offset) *offset = mOffset;
     if (size) *size = mSize;
-    return (mSize > 0) ? mHeap : 0;
+    return (mSize > 0) ? mHeap : nullptr;
 }
 
 // ---------------------------------------------------------------------------
@@ -225,6 +229,7 @@
 BnMemory::~BnMemory() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemory::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -234,8 +239,8 @@
             ssize_t offset;
             size_t size;
             reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) );
-            reply->writeInt32(offset);
-            reply->writeInt32(size);
+            reply->writeInt64(offset);
+            reply->writeUint64(size);
             return NO_ERROR;
         } break;
         default:
@@ -264,7 +269,6 @@
                 if (VERBOSE) {
                     ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d",
                             binder.get(), this, mSize, heapId);
-                    CallStack stack(LOG_TAG);
                 }
 
                 munmap(mBase, mSize);
@@ -315,18 +319,23 @@
         data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
         status_t err = remote()->transact(HEAP_ID, data, &reply);
         int parcel_fd = reply.readFileDescriptor();
-        ssize_t size = reply.readInt32();
-        uint32_t flags = reply.readInt32();
-        uint32_t offset = reply.readInt32();
-
-        ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)",
-                IInterface::asBinder(this).get(),
-                parcel_fd, size, err, strerror(-err));
+        const uint64_t size64 = reply.readUint64();
+        const int64_t offset64 = reply.readInt64();
+        const uint32_t flags = reply.readUint32();
+        const size_t size = (size_t)size64;
+        const off_t offset = (off_t)offset64;
+        if (err != NO_ERROR || // failed transaction
+                size != size64 || offset != offset64) { // ILP32 size check
+            ALOGE("binder=%p transaction failed fd=%d, size=%zu, err=%d (%s)",
+                    IInterface::asBinder(this).get(),
+                    parcel_fd, size, err, strerror(-err));
+            return;
+        }
 
         Mutex::Autolock _l(mLock);
         if (mHeapId.load(memory_order_relaxed) == -1) {
             int fd = fcntl(parcel_fd, F_DUPFD_CLOEXEC, 0);
-            ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
+            ALOGE_IF(fd == -1, "cannot dup fd=%d, size=%zu, err=%d (%s)",
                     parcel_fd, size, err, strerror(errno));
 
             int access = PROT_READ;
@@ -334,9 +343,9 @@
                 access |= PROT_WRITE;
             }
             mRealHeap = true;
-            mBase = mmap(0, size, access, MAP_SHARED, fd, offset);
+            mBase = mmap(nullptr, size, access, MAP_SHARED, fd, offset);
             if (mBase == MAP_FAILED) {
-                ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)",
+                ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zu, fd=%d (%s)",
                         IInterface::asBinder(this).get(), size, fd, strerror(errno));
                 close(fd);
             } else {
@@ -370,7 +379,7 @@
     return mFlags;
 }
 
-uint32_t BpMemoryHeap::getOffset() const {
+off_t BpMemoryHeap::getOffset() const {
     assertMapped();
     return mOffset;
 }
@@ -385,6 +394,7 @@
 BnMemoryHeap::~BnMemoryHeap() {
 }
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMemoryHeap::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -392,9 +402,9 @@
        case HEAP_ID: {
             CHECK_INTERFACE(IMemoryHeap, data, reply);
             reply->writeFileDescriptor(getHeapID());
-            reply->writeInt32(getSize());
-            reply->writeInt32(getFlags());
-            reply->writeInt32(getOffset());
+            reply->writeUint64(getSize());
+            reply->writeInt64(getOffset());
+            reply->writeUint32(getFlags());
             return NO_ERROR;
         } break;
         default:
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index fd552b4..9a561cb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -17,12 +17,15 @@
 #define LOG_TAG "IPCThreadState"
 
 #include <binder/IPCThreadState.h>
+#include <binderthreadstate/IPCThreadStateBase.h>
 
 #include <binder/Binder.h>
 #include <binder/BpBinder.h>
 #include <binder/TextOutput.h>
 
+#include <android-base/macros.h>
 #include <cutils/sched_policy.h>
+#include <utils/CallStack.h>
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 #include <utils/threads.h>
@@ -85,7 +88,8 @@
     "BR_FINISHED",
     "BR_DEAD_BINDER",
     "BR_CLEAR_DEATH_NOTIFICATION_DONE",
-    "BR_FAILED_REPLY"
+    "BR_FAILED_REPLY",
+    "BR_TRANSACTION_SEC_CTX",
 };
 
 static const char *kCommandStrings[] = {
@@ -108,6 +112,8 @@
     "BC_DEAD_BINDER_DONE"
 };
 
+static const int64_t kWorkSourcePropagatedBitIndex = 32;
+
 static const char* getReturnString(uint32_t cmd)
 {
     size_t idx = cmd & 0xff;
@@ -289,7 +295,7 @@
 
     if (gShutdown) {
         ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");
-        return NULL;
+        return nullptr;
     }
 
     pthread_mutex_lock(&gTLSMutex);
@@ -299,7 +305,7 @@
             pthread_mutex_unlock(&gTLSMutex);
             ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",
                     strerror(key_create_value));
-            return NULL;
+            return nullptr;
         }
         gHaveTLS = true;
     }
@@ -314,7 +320,7 @@
         IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
         return st;
     }
-    return NULL;
+    return nullptr;
 }
 
 void IPCThreadState::shutdown()
@@ -326,7 +332,7 @@
         IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
         if (st) {
             delete st;
-            pthread_setspecific(gTLS, NULL);
+            pthread_setspecific(gTLS, nullptr);
         }
         pthread_key_delete(gTLS);
         gHaveTLS = false;
@@ -360,6 +366,11 @@
     return mCallingPid;
 }
 
+const char* IPCThreadState::getCallingSid() const
+{
+    return mCallingSid;
+}
+
 uid_t IPCThreadState::getCallingUid() const
 {
     return mCallingUid;
@@ -367,6 +378,7 @@
 
 int64_t IPCThreadState::clearCallingIdentity()
 {
+    // ignore mCallingSid for legacy reasons
     int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
     clearCaller();
     return token;
@@ -382,6 +394,48 @@
     return mStrictModePolicy;
 }
 
+int64_t IPCThreadState::setCallingWorkSourceUid(uid_t uid)
+{
+    int64_t token = setCallingWorkSourceUidWithoutPropagation(uid);
+    mPropagateWorkSource = true;
+    return token;
+}
+
+int64_t IPCThreadState::setCallingWorkSourceUidWithoutPropagation(uid_t uid)
+{
+    const int64_t propagatedBit = ((int64_t)mPropagateWorkSource) << kWorkSourcePropagatedBitIndex;
+    int64_t token = propagatedBit | mWorkSource;
+    mWorkSource = uid;
+    return token;
+}
+
+void IPCThreadState::clearPropagateWorkSource()
+{
+    mPropagateWorkSource = false;
+}
+
+bool IPCThreadState::shouldPropagateWorkSource() const
+{
+    return mPropagateWorkSource;
+}
+
+uid_t IPCThreadState::getCallingWorkSourceUid() const
+{
+    return mWorkSource;
+}
+
+int64_t IPCThreadState::clearCallingWorkSource()
+{
+    return setCallingWorkSourceUid(kUnsetWorkSource);
+}
+
+void IPCThreadState::restoreCallingWorkSource(int64_t token)
+{
+    uid_t uid = (int)token;
+    setCallingWorkSourceUidWithoutPropagation(uid);
+    mPropagateWorkSource = ((token >> kWorkSourcePropagatedBitIndex) & 1) == 1;
+}
+
 void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
 {
     mLastTransactionBinderFlags = flags;
@@ -395,12 +449,14 @@
 void IPCThreadState::restoreCallingIdentity(int64_t token)
 {
     mCallingUid = (int)(token>>32);
+    mCallingSid = nullptr;  // not enough data to restore
     mCallingPid = (int)token;
 }
 
 void IPCThreadState::clearCaller()
 {
     mCallingPid = getpid();
+    mCallingSid = nullptr;  // expensive to lookup
     mCallingUid = getuid();
 }
 
@@ -608,7 +664,7 @@
 
     LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
         (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
-    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
+    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
 
     if (err != NO_ERROR) {
         if (reply) reply->setError(err);
@@ -616,6 +672,16 @@
     }
 
     if ((flags & TF_ONE_WAY) == 0) {
+        if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
+            if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
+                ALOGE("Process making non-oneway call but is restricted.");
+                CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
+                    ANDROID_LOG_ERROR);
+            } else /* FATAL_IF_NOT_ONEWAY */ {
+                LOG_ALWAYS_FATAL("Process may not make oneway calls.");
+            }
+        }
+
         #if 0
         if (code == 4) { // relayout
             ALOGI(">>>>>> CALLING transaction 4");
@@ -645,7 +711,7 @@
             else alog << "(none requested)" << endl;
         }
     } else {
-        err = waitForResponse(NULL, NULL);
+        err = waitForResponse(nullptr, nullptr);
     }
 
     return err;
@@ -735,13 +801,17 @@
 
 IPCThreadState::IPCThreadState()
     : mProcess(ProcessState::self()),
+      mWorkSource(kUnsetWorkSource),
+      mPropagateWorkSource(false),
       mStrictModePolicy(0),
-      mLastTransactionBinderFlags(0)
+      mLastTransactionBinderFlags(0),
+      mCallRestriction(mProcess->mCallRestriction)
 {
     pthread_setspecific(gTLS, this);
     clearCaller();
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
+    mIPCThreadStateBase = IPCThreadStateBase::self();
 }
 
 IPCThreadState::~IPCThreadState()
@@ -755,7 +825,7 @@
     err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
     if (err < NO_ERROR) return err;
 
-    return waitForResponse(NULL, NULL);
+    return waitForResponse(nullptr, nullptr);
 }
 
 status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
@@ -815,14 +885,14 @@
                             freeBuffer, this);
                     } else {
                         err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
-                        freeBuffer(NULL,
+                        freeBuffer(nullptr,
                             reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                             tr.data_size,
                             reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                             tr.offsets_size/sizeof(binder_size_t), this);
                     }
                 } else {
-                    freeBuffer(NULL,
+                    freeBuffer(nullptr,
                         reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                         tr.data_size,
                         reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
@@ -1074,14 +1144,26 @@
         }
         break;
 
+    case BR_TRANSACTION_SEC_CTX:
     case BR_TRANSACTION:
         {
-            binder_transaction_data tr;
-            result = mIn.read(&tr, sizeof(tr));
+            binder_transaction_data_secctx tr_secctx;
+            binder_transaction_data& tr = tr_secctx.transaction_data;
+
+            if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
+                result = mIn.read(&tr_secctx, sizeof(tr_secctx));
+            } else {
+                result = mIn.read(&tr, sizeof(tr));
+                tr_secctx.secctx = 0;
+            }
+
             ALOG_ASSERT(result == NO_ERROR,
                 "Not enough command data for brTRANSACTION");
             if (result != NO_ERROR) break;
 
+            //Record the fact that we're in a binder call.
+            mIPCThreadStateBase->pushCurrentState(
+                IPCThreadStateBase::CallState::BINDER);
             Parcel buffer;
             buffer.ipcSetDataReference(
                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1090,15 +1172,25 @@
                 tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
 
             const pid_t origPid = mCallingPid;
+            const char* origSid = mCallingSid;
             const uid_t origUid = mCallingUid;
             const int32_t origStrictModePolicy = mStrictModePolicy;
             const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
+            const int32_t origWorkSource = mWorkSource;
+            const bool origPropagateWorkSet = mPropagateWorkSource;
+            // Calling work source will be set by Parcel#enforceInterface. Parcel#enforceInterface
+            // is only guaranteed to be called for AIDL-generated stubs so we reset the work source
+            // here to never propagate it.
+            clearCallingWorkSource();
+            clearPropagateWorkSource();
 
             mCallingPid = tr.sender_pid;
+            mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
             mCallingUid = tr.sender_euid;
             mLastTransactionBinderFlags = tr.flags;
 
-            //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+            // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
+            //    (mCallingSid ? mCallingSid : "<N/A>"), mCallingUid);
 
             Parcel reply;
             status_t error;
@@ -1129,8 +1221,9 @@
                 error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
             }
 
-            //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
-            //     mCallingPid, origPid, origUid);
+            mIPCThreadStateBase->popCurrentState();
+            //ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
+            //     mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);
 
             if ((tr.flags & TF_ONE_WAY) == 0) {
                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);
@@ -1141,9 +1234,12 @@
             }
 
             mCallingPid = origPid;
+            mCallingSid = origSid;
             mCallingUid = origUid;
             mStrictModePolicy = origStrictModePolicy;
             mLastTransactionBinderFlags = origTransactionBinderFlags;
+            mWorkSource = origWorkSource;
+            mPropagateWorkSource = origPropagateWorkSet;
 
             IF_LOG_TRANSACTIONS() {
                 TextOutput::Bundle _b(alog);
@@ -1192,6 +1288,10 @@
     return result;
 }
 
+bool IPCThreadState::isServingCall() const {
+    return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
+}
+
 void IPCThreadState::threadDestructor(void *st)
 {
         IPCThreadState* const self = static_cast<IPCThreadState*>(st);
@@ -1217,7 +1317,7 @@
         alog << "Writing BC_FREE_BUFFER for " << data << endl;
     }
     ALOG_ASSERT(data != NULL, "Called with NULL data");
-    if (parcel != NULL) parcel->closeFileDescriptors();
+    if (parcel != nullptr) parcel->closeFileDescriptors();
     IPCThreadState* state = self();
     state->mOut.writeInt32(BC_FREE_BUFFER);
     state->mOut.writePointer((uintptr_t)data);
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 89ebc6c..6b99150 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -109,6 +109,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnPermissionController::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 646809e..159763d 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -40,7 +40,7 @@
         Parcel data;
         data.writeInterfaceToken(IResultReceiver::getInterfaceDescriptor());
         data.writeInt32(resultCode);
-        remote()->transact(OP_SEND, data, NULL, IBinder::FLAG_ONEWAY);
+        remote()->transact(OP_SEND, data, nullptr, IBinder::FLAG_ONEWAY);
     }
 };
 
@@ -48,6 +48,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnResultReceiver::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -56,7 +57,7 @@
             CHECK_INTERFACE(IResultReceiver, data, reply);
             int32_t resultCode = data.readInt32();
             send(resultCode);
-            if (reply != NULL) {
+            if (reply != nullptr) {
                 reply->writeNoException();
             }
             return NO_ERROR;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 4896f68..4ba6c2a 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -27,7 +27,6 @@
 #include <cutils/properties.h>
 #include <utils/String8.h>
 #include <utils/SystemClock.h>
-#include <utils/CallStack.h>
 
 #include <private/binder/Static.h>
 
@@ -37,14 +36,14 @@
 
 sp<IServiceManager> defaultServiceManager()
 {
-    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
+    if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
 
     {
         AutoMutex _l(gDefaultServiceManagerLock);
-        while (gDefaultServiceManager == NULL) {
+        while (gDefaultServiceManager == nullptr) {
             gDefaultServiceManager = interface_cast<IServiceManager>(
-                ProcessState::self()->getContextObject(NULL));
-            if (gDefaultServiceManager == NULL)
+                ProcessState::self()->getContextObject(nullptr));
+            if (gDefaultServiceManager == nullptr)
                 sleep(1);
         }
     }
@@ -57,7 +56,7 @@
 
 bool checkCallingPermission(const String16& permission)
 {
-    return checkCallingPermission(permission, NULL, NULL);
+    return checkCallingPermission(permission, nullptr, nullptr);
 }
 
 static String16 _permission("permission");
@@ -83,7 +82,7 @@
     int64_t startTime = 0;
 
     while (true) {
-        if (pc != NULL) {
+        if (pc != nullptr) {
             bool res = pc->checkPermission(permission, pid, uid);
             if (res) {
                 if (startTime != 0) {
@@ -104,14 +103,14 @@
             // Object is dead!
             gDefaultServiceManagerLock.lock();
             if (gPermissionController == pc) {
-                gPermissionController = NULL;
+                gPermissionController = nullptr;
             }
             gDefaultServiceManagerLock.unlock();
         }
 
         // Need to retrieve the permission controller.
         sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
-        if (binder == NULL) {
+        if (binder == nullptr) {
             // Wait for the permission controller to come back...
             if (startTime == 0) {
                 startTime = uptimeMillis();
@@ -144,7 +143,7 @@
     virtual sp<IBinder> getService(const String16& name) const
     {
         sp<IBinder> svc = checkService(name);
-        if (svc != NULL) return svc;
+        if (svc != nullptr) return svc;
 
         const bool isVendorService =
             strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
@@ -161,19 +160,15 @@
         int n = 0;
         while (uptimeMillis() < timeout) {
             n++;
-            if (isVendorService) {
-                ALOGI("Waiting for vendor service %s...", String8(name).string());
-                CallStack stack(LOG_TAG);
-            } else if (n%10 == 0) {
-                ALOGI("Waiting for service %s...", String8(name).string());
-            }
+            ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+                ProcessState::self()->getDriverName().c_str());
             usleep(1000*sleepTime);
 
             sp<IBinder> svc = checkService(name);
-            if (svc != NULL) return svc;
+            if (svc != nullptr) return svc;
         }
         ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
-        return NULL;
+        return nullptr;
     }
 
     virtual sp<IBinder> checkService( const String16& name) const
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index 23b83a6..6c697de 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -58,6 +58,7 @@
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnShellCallback::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -68,7 +69,7 @@
             String16 seLinuxContext(data.readString16());
             String16 mode(data.readString16());
             int fd = openFile(path, seLinuxContext, mode);
-            if (reply != NULL) {
+            if (reply != nullptr) {
                 reply->writeNoException();
                 if (fd >= 0) {
                     reply->writeInt32(1);
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index 697e948..82f9047 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -55,6 +55,16 @@
         data.writeInt32(disabled ? 1 : 0);
         remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(procState);
+        data.writeInt64(procStateSeq);
+        remote()->transact(ON_UID_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 // ----------------------------------------------------------------------
@@ -89,6 +99,14 @@
             onUidIdle(uid, disabled);
             return NO_ERROR;
         } break;
+        case ON_UID_STATE_CHANGED_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            int32_t procState = data.readInt32();
+            int64_t procStateSeq = data.readInt64();
+            onUidStateChanged(uid, procState, procStateSeq);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 1cfe02a..eacad3b 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -52,8 +52,8 @@
     NODE*  mLast;
 
 public:
-                LinkedList() : mFirst(0), mLast(0) { }
-    bool        isEmpty() const { return mFirst == 0; }
+                LinkedList() : mFirst(nullptr), mLast(nullptr) { }
+    bool        isEmpty() const { return mFirst == nullptr; }
     NODE const* head() const { return mFirst; }
     NODE*       head() { return mFirst; }
     NODE const* tail() const { return mLast; }
@@ -62,7 +62,7 @@
     void insertAfter(NODE* node, NODE* newNode) {
         newNode->prev = node;
         newNode->next = node->next;
-        if (node->next == 0) mLast = newNode;
+        if (node->next == nullptr) mLast = newNode;
         else                 node->next->prev = newNode;
         node->next = newNode;
     }
@@ -70,17 +70,17 @@
     void insertBefore(NODE* node, NODE* newNode) {
          newNode->prev = node->prev;
          newNode->next = node;
-         if (node->prev == 0)   mFirst = newNode;
+         if (node->prev == nullptr)   mFirst = newNode;
          else                   node->prev->next = newNode;
          node->prev = newNode;
     }
 
     void insertHead(NODE* newNode) {
-        if (mFirst == 0) {
+        if (mFirst == nullptr) {
             mFirst = mLast = newNode;
-            newNode->prev = newNode->next = 0;
+            newNode->prev = newNode->next = nullptr;
         } else {
-            newNode->prev = 0;
+            newNode->prev = nullptr;
             newNode->next = mFirst;
             mFirst->prev = newNode;
             mFirst = newNode;
@@ -99,9 +99,9 @@
     }
 
     NODE* remove(NODE* node) {
-        if (node->prev == 0)    mFirst = node->next;
+        if (node->prev == nullptr)    mFirst = node->next;
         else                    node->prev->next = node->next;
-        if (node->next == 0)    mLast = node->prev;
+        if (node->next == nullptr)    mLast = node->prev;
         else                    node->next->prev = node->prev;
         return node;
     }
@@ -141,7 +141,7 @@
 
     struct chunk_t {
         chunk_t(size_t start, size_t size)
-        : start(start), size(size), free(1), prev(0), next(0) {
+        : start(start), size(size), free(1), prev(nullptr), next(nullptr) {
         }
         size_t              start;
         size_t              size : 28;
@@ -329,7 +329,7 @@
         return 0;
     }
     size = (size + kMemoryAlign-1) / kMemoryAlign;
-    chunk_t* free_chunk = 0;
+    chunk_t* free_chunk = nullptr;
     chunk_t* cur = mList.head();
 
     size_t pagesize = getpagesize();
@@ -418,7 +418,7 @@
         }
         cur = cur->next;
     }
-    return 0;
+    return nullptr;
 }
 
 void SimpleBestFitAllocator::dump(const char* what) const
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 03f00be..4c300b4 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -36,17 +36,17 @@
 
 MemoryHeapBase::MemoryHeapBase()
     : mFD(-1), mSize(0), mBase(MAP_FAILED),
-      mDevice(NULL), mNeedUnmap(false), mOffset(0)
+      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
 }
 
 MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
-      mDevice(0), mNeedUnmap(false), mOffset(0)
+      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
-    int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
+    int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
     ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
     if (fd >= 0) {
         if (mapfd(fd, size) == NO_ERROR) {
@@ -59,7 +59,7 @@
 
 MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
-      mDevice(0), mNeedUnmap(false), mOffset(0)
+      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
     int open_flags = O_RDWR;
     if (flags & NO_CACHING)
@@ -76,16 +76,16 @@
     }
 }
 
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
-      mDevice(0), mNeedUnmap(false), mOffset(0)
+      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
     mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
 }
 
-status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
 {
     if (mFD != -1) {
         return INVALID_OPERATION;
@@ -98,30 +98,37 @@
     return NO_ERROR;
 }
 
-status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
+status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
 {
     if (size == 0) {
         // try to figure out the size automatically
         struct stat sb;
-        if (fstat(fd, &sb) == 0)
-            size = sb.st_size;
+        if (fstat(fd, &sb) == 0) {
+            size = (size_t)sb.st_size;
+            // sb.st_size is off_t which on ILP32 may be 64 bits while size_t is 32 bits.
+            if ((off_t)size != sb.st_size) {
+                ALOGE("%s: size of file %lld cannot fit in memory",
+                        __func__, (long long)sb.st_size);
+                return INVALID_OPERATION;
+            }
+        }
         // if it didn't work, let mmap() fail.
     }
 
     if ((mFlags & DONT_MAP_LOCALLY) == 0) {
-        void* base = (uint8_t*)mmap(0, size,
+        void* base = (uint8_t*)mmap(nullptr, size,
                 PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
         if (base == MAP_FAILED) {
-            ALOGE("mmap(fd=%d, size=%u) failed (%s)",
-                    fd, uint32_t(size), strerror(errno));
+            ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
+                    fd, size, strerror(errno));
             close(fd);
             return -errno;
         }
-        //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+        //ALOGD("mmap(fd=%d, base=%p, size=%zu)", fd, base, size);
         mBase = base;
         mNeedUnmap = true;
     } else  {
-        mBase = 0; // not MAP_FAILED
+        mBase = nullptr; // not MAP_FAILED
         mNeedUnmap = false;
     }
     mFD = fd;
@@ -140,10 +147,10 @@
     int fd = android_atomic_or(-1, &mFD);
     if (fd >= 0) {
         if (mNeedUnmap) {
-            //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+            //ALOGD("munmap(fd=%d, base=%p, size=%zu)", fd, mBase, mSize);
             munmap(mBase, mSize);
         }
-        mBase = 0;
+        mBase = nullptr;
         mSize = 0;
         close(fd);
     }
@@ -169,7 +176,7 @@
     return mDevice;
 }
 
-uint32_t MemoryHeapBase::getOffset() const {
+off_t MemoryHeapBase::getOffset() const {
     return mOffset;
 }
 
diff --git a/libs/binder/OWNERS b/libs/binder/OWNERS
new file mode 100644
index 0000000..350994a
--- /dev/null
+++ b/libs/binder/OWNERS
@@ -0,0 +1,5 @@
+arve@google.com
+ctate@google.com
+hackbod@google.com
+maco@google.com
+smoreland@google.com
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 43e4580..5ad3027 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -74,15 +74,7 @@
 }
 
 // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
-#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
-
-// XXX This can be made public if we want to provide
-// support for typed data.
-struct small_flat_data
-{
-    uint32_t type;
-    uint32_t data;
-};
+#define STRICT_MODE_PENALTY_GATHER (1 << 31)
 
 namespace android {
 
@@ -117,7 +109,7 @@
             return;
         case BINDER_TYPE_HANDLE: {
             const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
-            if (b != NULL) {
+            if (b != nullptr) {
                 LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
                 b->incStrong(who);
             }
@@ -125,11 +117,11 @@
         }
         case BINDER_TYPE_WEAK_HANDLE: {
             const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
-            if (b != NULL) b.get_refs()->incWeak(who);
+            if (b != nullptr) b.get_refs()->incWeak(who);
             return;
         }
         case BINDER_TYPE_FD: {
-            if ((obj.cookie != 0) && (outAshmemSize != NULL) && ashmem_valid(obj.handle)) {
+            if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
                 // If we own an ashmem fd, keep track of how much memory it refers to.
                 int size = ashmem_get_size_region(obj.handle);
                 if (size > 0) {
@@ -146,7 +138,7 @@
 void acquire_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who)
 {
-    acquire_object(proc, obj, who, NULL);
+    acquire_object(proc, obj, who, nullptr);
 }
 
 static void release_object(const sp<ProcessState>& proc,
@@ -165,7 +157,7 @@
             return;
         case BINDER_TYPE_HANDLE: {
             const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
-            if (b != NULL) {
+            if (b != nullptr) {
                 LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
                 b->decStrong(who);
             }
@@ -173,15 +165,18 @@
         }
         case BINDER_TYPE_WEAK_HANDLE: {
             const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
-            if (b != NULL) b.get_refs()->decWeak(who);
+            if (b != nullptr) b.get_refs()->decWeak(who);
             return;
         }
         case BINDER_TYPE_FD: {
             if (obj.cookie != 0) { // owned
-                if ((outAshmemSize != NULL) && ashmem_valid(obj.handle)) {
+                if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
                     int size = ashmem_get_size_region(obj.handle);
                     if (size > 0) {
-                        *outAshmemSize -= size;
+                        // ashmem size might have changed since last time it was accounted for, e.g.
+                        // in acquire_object(). Value of *outAshmemSize is not critical since we are
+                        // releasing the object anyway. Check for integer overflow condition.
+                        *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
                     }
                 }
 
@@ -197,7 +192,7 @@
 void release_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who)
 {
-    release_object(proc, obj, who, NULL);
+    release_object(proc, obj, who, nullptr);
 }
 
 inline static status_t finish_flatten_binder(
@@ -219,11 +214,11 @@
         obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
     }
 
-    if (binder != NULL) {
-        IBinder *local = binder->localBinder();
+    if (binder != nullptr) {
+        BBinder *local = binder->localBinder();
         if (!local) {
             BpBinder *proxy = binder->remoteBinder();
-            if (proxy == NULL) {
+            if (proxy == nullptr) {
                 ALOGE("null proxy");
             }
             const int32_t handle = proxy ? proxy->handle() : 0;
@@ -232,6 +227,9 @@
             obj.handle = handle;
             obj.cookie = 0;
         } else {
+            if (local->isRequestingSid()) {
+                obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+            }
             obj.hdr.type = BINDER_TYPE_BINDER;
             obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
             obj.cookie = reinterpret_cast<uintptr_t>(local);
@@ -251,13 +249,13 @@
     flat_binder_object obj;
 
     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
-    if (binder != NULL) {
+    if (binder != nullptr) {
         sp<IBinder> real = binder.promote();
-        if (real != NULL) {
+        if (real != nullptr) {
             IBinder *local = real->localBinder();
             if (!local) {
                 BpBinder *proxy = real->remoteBinder();
-                if (proxy == NULL) {
+                if (proxy == nullptr) {
                     ALOGE("null proxy");
                 }
                 const int32_t handle = proxy ? proxy->handle() : 0;
@@ -284,13 +282,13 @@
         obj.hdr.type = BINDER_TYPE_BINDER;
         obj.binder = 0;
         obj.cookie = 0;
-        return finish_flatten_binder(NULL, obj, out);
+        return finish_flatten_binder(nullptr, obj, out);
 
     } else {
         obj.hdr.type = BINDER_TYPE_BINDER;
         obj.binder = 0;
         obj.cookie = 0;
-        return finish_flatten_binder(NULL, obj, out);
+        return finish_flatten_binder(nullptr, obj, out);
     }
 }
 
@@ -310,7 +308,7 @@
         switch (flat->hdr.type) {
             case BINDER_TYPE_BINDER:
                 *out = reinterpret_cast<IBinder*>(flat->cookie);
-                return finish_unflatten_binder(NULL, *flat, in);
+                return finish_unflatten_binder(nullptr, *flat, in);
             case BINDER_TYPE_HANDLE:
                 *out = proc->getStrongProxyForHandle(flat->handle);
                 return finish_unflatten_binder(
@@ -329,16 +327,16 @@
         switch (flat->hdr.type) {
             case BINDER_TYPE_BINDER:
                 *out = reinterpret_cast<IBinder*>(flat->cookie);
-                return finish_unflatten_binder(NULL, *flat, in);
+                return finish_unflatten_binder(nullptr, *flat, in);
             case BINDER_TYPE_WEAK_BINDER:
                 if (flat->binder != 0) {
                     out->set_object_and_refs(
                         reinterpret_cast<IBinder*>(flat->cookie),
                         reinterpret_cast<RefBase::weakref_type*>(flat->binder));
                 } else {
-                    *out = NULL;
+                    *out = nullptr;
                 }
-                return finish_unflatten_binder(NULL, *flat, in);
+                return finish_unflatten_binder(nullptr, *flat, in);
             case BINDER_TYPE_HANDLE:
             case BINDER_TYPE_WEAK_HANDLE:
                 *out = proc->getWeakProxyForHandle(flat->handle);
@@ -467,7 +465,6 @@
 
 status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
 {
-    const sp<ProcessState> proc(ProcessState::self());
     status_t err;
     const uint8_t *data = parcel->mData;
     const binder_size_t *objects = parcel->mObjects;
@@ -520,13 +517,14 @@
     err = NO_ERROR;
 
     if (numObjects > 0) {
+        const sp<ProcessState> proc(ProcessState::self());
         // grow objects
         if (mObjectsCapacity < mObjectsSize + numObjects) {
             size_t newSize = ((mObjectsSize + numObjects)*3)/2;
             if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY;   // overflow
             binder_size_t *objects =
                 (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
-            if (objects == (binder_size_t*)0) {
+            if (objects == (binder_size_t*)nullptr) {
                 return NO_MEMORY;
             }
             mObjects = objects;
@@ -596,15 +594,53 @@
     return mHasFds;
 }
 
+void Parcel::updateWorkSourceRequestHeaderPosition() const {
+    // Only update the request headers once. We only want to point
+    // to the first headers read/written.
+    if (!mRequestHeaderPresent) {
+        mWorkSourceRequestHeaderPosition = dataPosition();
+        mRequestHeaderPresent = true;
+    }
+}
+
 // Write RPC headers.  (previously just the interface token)
 status_t Parcel::writeInterfaceToken(const String16& interface)
 {
-    writeInt32(IPCThreadState::self()->getStrictModePolicy() |
-               STRICT_MODE_PENALTY_GATHER);
+    const IPCThreadState* threadState = IPCThreadState::self();
+    writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+    updateWorkSourceRequestHeaderPosition();
+    writeInt32(threadState->shouldPropagateWorkSource() ?
+            threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
     // currently the interface identification token is just its name as a string
     return writeString16(interface);
 }
 
+bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
+{
+    if (!mRequestHeaderPresent) {
+        return false;
+    }
+
+    const size_t initialPosition = dataPosition();
+    setDataPosition(mWorkSourceRequestHeaderPosition);
+    status_t err = writeInt32(uid);
+    setDataPosition(initialPosition);
+    return err == NO_ERROR;
+}
+
+uid_t Parcel::readCallingWorkSourceUid()
+{
+    if (!mRequestHeaderPresent) {
+        return IPCThreadState::kUnsetWorkSource;
+    }
+
+    const size_t initialPosition = dataPosition();
+    setDataPosition(mWorkSourceRequestHeaderPosition);
+    uid_t uid = readInt32();
+    setDataPosition(initialPosition);
+    return uid;
+}
+
 bool Parcel::checkInterface(IBinder* binder) const
 {
     return enforceInterface(binder->getInterfaceDescriptor());
@@ -613,8 +649,9 @@
 bool Parcel::enforceInterface(const String16& interface,
                               IPCThreadState* threadState) const
 {
+    // StrictModePolicy.
     int32_t strictPolicy = readInt32();
-    if (threadState == NULL) {
+    if (threadState == nullptr) {
         threadState = IPCThreadState::self();
     }
     if ((threadState->getLastTransactionBinderFlags() &
@@ -627,6 +664,11 @@
     } else {
       threadState->setStrictModePolicy(strictPolicy);
     }
+    // WorkSource.
+    updateWorkSourceRequestHeaderPosition();
+    int32_t workSource = readInt32();
+    threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
+    // Interface descriptor.
     const String16 str(readString16());
     if (str == interface) {
         return true;
@@ -722,14 +764,14 @@
     if (len > INT32_MAX) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
-        return NULL;
+        return nullptr;
     }
 
     const size_t padded = pad_size(len);
 
     // sanity check for integer overflow
     if (mDataPos+padded < mDataPos) {
-        return NULL;
+        return nullptr;
     }
 
     if ((mDataPos+padded) <= mDataCapacity) {
@@ -760,7 +802,7 @@
 
     status_t err = growData(padded);
     if (err == NO_ERROR) goto restart_write;
-    return NULL;
+    return nullptr;
 }
 
 status_t Parcel::writeUtf8AsUtf16(const std::string& str) {
@@ -871,6 +913,16 @@
     return writeNullableTypedVector(val, &Parcel::writeInt64);
 }
 
+status_t Parcel::writeUint64Vector(const std::vector<uint64_t>& val)
+{
+    return writeTypedVector(val, &Parcel::writeUint64);
+}
+
+status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeUint64);
+}
+
 status_t Parcel::writeFloatVector(const std::vector<float>& val)
 {
     return writeTypedVector(val, &Parcel::writeFloat);
@@ -1063,7 +1115,7 @@
 
 status_t Parcel::writeString16(const char16_t* str, size_t len)
 {
-    if (str == NULL) return writeInt32(-1);
+    if (str == nullptr) return writeInt32(-1);
 
     status_t err = writeInt32(len);
     if (err == NO_ERROR) {
@@ -1180,6 +1232,19 @@
     return writeFileDescriptor(fd, takeOwnership);
 }
 
+status_t Parcel::writeDupParcelFileDescriptor(int fd)
+{
+    int dupFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+    if (dupFd < 0) {
+        return -errno;
+    }
+    status_t err = writeParcelFileDescriptor(dupFd, true /*takeOwnership*/);
+    if (err != OK) {
+        close(dupFd);
+    }
+    return err;
+}
+
 status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) {
     return writeDupFileDescriptor(fd.get());
 }
@@ -1221,7 +1286,7 @@
     if (result < 0) {
         status = result;
     } else {
-        void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        void* ptr = ::mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
         if (ptr == MAP_FAILED) {
             status = -errno;
         } else {
@@ -1278,10 +1343,10 @@
 
     // payload
     void* const buf = this->writeInplace(len);
-    if (buf == NULL)
+    if (buf == nullptr)
         return BAD_VALUE;
 
-    int* fds = NULL;
+    int* fds = nullptr;
     if (fd_count) {
         fds = new (std::nothrow) int[fd_count];
         if (fds == nullptr) {
@@ -1337,7 +1402,7 @@
         size_t newSize = ((mObjectsSize+2)*3)/2;
         if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY;   // overflow
         binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
-        if (objects == NULL) return NO_MEMORY;
+        if (objects == nullptr) return NO_MEMORY;
         mObjects = objects;
         mObjectsCapacity = newSize;
     }
@@ -1383,7 +1448,7 @@
 
 status_t Parcel::writeNullableMap(const std::unique_ptr<binder::Map>& map)
 {
-    if (map == NULL) {
+    if (map == nullptr) {
         return writeInt32(-1);
     }
 
@@ -1555,7 +1620,7 @@
     if (len > INT32_MAX) {
         // don't accept size_t values which may have come from an
         // inadvertent conversion from a negative int.
-        return NULL;
+        return nullptr;
     }
 
     if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
@@ -1566,7 +1631,7 @@
                 // Still increment the data position by the expected length
                 mDataPos += pad_size(len);
                 ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
-                return NULL;
+                return nullptr;
             }
         }
 
@@ -1575,7 +1640,7 @@
         ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
         return data;
     }
-    return NULL;
+    return nullptr;
 }
 
 template<class T>
@@ -1719,6 +1784,14 @@
     return readTypedVector(val, &Parcel::readInt64);
 }
 
+status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readUint64);
+}
+
+status_t Parcel::readUint64Vector(std::vector<uint64_t>* val) const {
+    return readTypedVector(val, &Parcel::readUint64);
+}
+
 status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const {
     return readNullableTypedVector(val, &Parcel::readFloat);
 }
@@ -2025,7 +2098,7 @@
             return str;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 String8 Parcel::readString8() const
@@ -2056,7 +2129,7 @@
         return OK;
     }
     const char* str = (const char*)readInplace(size + 1);
-    if (str == NULL) {
+    if (str == nullptr) {
         return BAD_VALUE;
     }
     pArg->setTo(str, size);
@@ -2115,12 +2188,12 @@
     if (size >= 0 && size < INT32_MAX) {
         *outLen = size;
         const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
-        if (str != NULL) {
+        if (str != nullptr) {
             return str;
         }
     }
     *outLen = 0;
-    return NULL;
+    return nullptr;
 }
 
 status_t Parcel::readStrongBinder(sp<IBinder>* val) const
@@ -2182,13 +2255,13 @@
     int numFds, numInts;
     status_t err;
     err = readInt32(&numFds);
-    if (err != NO_ERROR) return 0;
+    if (err != NO_ERROR) return nullptr;
     err = readInt32(&numInts);
-    if (err != NO_ERROR) return 0;
+    if (err != NO_ERROR) return nullptr;
 
     native_handle* h = native_handle_create(numFds, numInts);
     if (!h) {
-        return 0;
+        return nullptr;
     }
 
     for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
@@ -2198,14 +2271,14 @@
                 close(h->data[j]);
             }
             native_handle_delete(h);
-            return 0;
+            return nullptr;
         }
     }
     err = read(h->data + numFds, sizeof(int)*numInts);
     if (err != NO_ERROR) {
         native_handle_close(h);
         native_handle_delete(h);
-        h = 0;
+        h = nullptr;
     }
     return h;
 }
@@ -2226,8 +2299,30 @@
     int32_t hasComm = readInt32();
     int fd = readFileDescriptor();
     if (hasComm != 0) {
-        // skip
-        readFileDescriptor();
+        // detach (owned by the binder driver)
+        int comm = readFileDescriptor();
+
+        // warning: this must be kept in sync with:
+        // frameworks/base/core/java/android/os/ParcelFileDescriptor.java
+        enum ParcelFileDescriptorStatus {
+            DETACHED = 2,
+        };
+
+#if BYTE_ORDER == BIG_ENDIAN
+        const int32_t message = ParcelFileDescriptorStatus::DETACHED;
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+        const int32_t message = __builtin_bswap32(ParcelFileDescriptorStatus::DETACHED);
+#endif
+
+        ssize_t written = TEMP_FAILURE_RETRY(
+            ::write(comm, &message, sizeof(message)));
+
+        if (written == -1 || written != sizeof(message)) {
+            ALOGW("Failed to detach ParcelFileDescriptor written: %zd err: %s",
+                written, strerror(errno));
+            return BAD_TYPE;
+        }
     }
     return fd;
 }
@@ -2249,6 +2344,22 @@
     return OK;
 }
 
+status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const
+{
+    int got = readParcelFileDescriptor();
+
+    if (got == BAD_TYPE) {
+        return BAD_TYPE;
+    }
+
+    val->reset(fcntl(got, F_DUPFD_CLOEXEC, 0));
+
+    if (val->get() < 0) {
+        return BAD_VALUE;
+    }
+
+    return OK;
+}
 
 status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
     return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
@@ -2278,7 +2389,16 @@
     int fd = readFileDescriptor();
     if (fd == int(BAD_TYPE)) return BAD_VALUE;
 
-    void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
+    if (!ashmem_valid(fd)) {
+        ALOGE("invalid fd");
+        return BAD_VALUE;
+    }
+    int size = ashmem_get_size_region(fd);
+    if (size < 0 || size_t(size) < len) {
+        ALOGE("request size %zu does not match fd size %d", len, size);
+        return BAD_VALUE;
+    }
+    void* ptr = ::mmap(nullptr, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
             MAP_SHARED, fd, 0);
     if (ptr == MAP_FAILED) return NO_MEMORY;
 
@@ -2300,10 +2420,10 @@
 
     // payload
     void const* const buf = this->readInplace(pad_size(len));
-    if (buf == NULL)
+    if (buf == nullptr)
         return BAD_VALUE;
 
-    int* fds = NULL;
+    int* fds = nullptr;
     if (fd_count) {
         fds = new (std::nothrow) int[fd_count];
         if (fds == nullptr) {
@@ -2394,7 +2514,7 @@
         ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object list",
              this, DPOS);
     }
-    return NULL;
+    return nullptr;
 }
 
 void Parcel::closeFileDescriptors()
@@ -2492,8 +2612,11 @@
 
 void Parcel::releaseObjects()
 {
-    const sp<ProcessState> proc(ProcessState::self());
     size_t i = mObjectsSize;
+    if (i == 0) {
+        return;
+    }
+    sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
     binder_size_t* const objects = mObjects;
     while (i > 0) {
@@ -2506,8 +2629,11 @@
 
 void Parcel::acquireObjects()
 {
-    const sp<ProcessState> proc(ProcessState::self());
     size_t i = mObjectsSize;
+    if (i == 0) {
+        return;
+    }
+    const sp<ProcessState> proc(ProcessState::self());
     uint8_t* const data = mData;
     binder_size_t* const objects = mObjects;
     while (i > 0) {
@@ -2604,7 +2730,7 @@
     ALOGV("restartWrite Setting data pos of %p to %zu", this, mDataPos);
 
     free(mObjects);
-    mObjects = NULL;
+    mObjects = nullptr;
     mObjectsSize = mObjectsCapacity = 0;
     mNextObjectHint = 0;
     mObjectsSorted = false;
@@ -2652,7 +2778,7 @@
             mError = NO_MEMORY;
             return NO_MEMORY;
         }
-        binder_size_t* objects = NULL;
+        binder_size_t* objects = nullptr;
 
         if (objectsSize) {
             objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));
@@ -2679,7 +2805,7 @@
         }
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
         mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
-        mOwner = NULL;
+        mOwner = nullptr;
 
         LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired);
         pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
@@ -2762,7 +2888,7 @@
             return NO_MEMORY;
         }
 
-        if(!(mDataCapacity == 0 && mObjects == NULL
+        if(!(mDataCapacity == 0 && mObjects == nullptr
              && mObjectsCapacity == 0)) {
             ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired);
         }
@@ -2787,13 +2913,13 @@
 {
     LOG_ALLOC("Parcel %p: initState", this);
     mError = NO_ERROR;
-    mData = 0;
+    mData = nullptr;
     mDataSize = 0;
     mDataCapacity = 0;
     mDataPos = 0;
     ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
     ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
-    mObjects = NULL;
+    mObjects = nullptr;
     mObjectsSize = 0;
     mObjectsCapacity = 0;
     mNextObjectHint = 0;
@@ -2801,8 +2927,10 @@
     mHasFds = false;
     mFdsKnown = true;
     mAllowFds = true;
-    mOwner = NULL;
+    mOwner = nullptr;
     mOpenAshmemSize = 0;
+    mWorkSourceRequestHeaderPosition = 0;
+    mRequestHeaderPresent = false;
 
     // racing multiple init leads only to multiple identical write
     if (gMaxFds == 0) {
@@ -2848,7 +2976,7 @@
 // --- Parcel::Blob ---
 
 Parcel::Blob::Blob() :
-        mFd(-1), mData(NULL), mSize(0), mMutable(false) {
+        mFd(-1), mData(nullptr), mSize(0), mMutable(false) {
 }
 
 Parcel::Blob::~Blob() {
@@ -2871,7 +2999,7 @@
 
 void Parcel::Blob::clear() {
     mFd = -1;
-    mData = NULL;
+    mData = nullptr;
     mSize = 0;
     mMutable = false;
 }
diff --git a/libs/binder/ParcelFileDescriptor.cpp b/libs/binder/ParcelFileDescriptor.cpp
new file mode 100644
index 0000000..4f8b76f
--- /dev/null
+++ b/libs/binder/ParcelFileDescriptor.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/ParcelFileDescriptor.h>
+
+namespace android {
+namespace os {
+
+ParcelFileDescriptor::ParcelFileDescriptor() = default;
+
+ParcelFileDescriptor::ParcelFileDescriptor(android::base::unique_fd fd) : mFd(std::move(fd)) {}
+
+ParcelFileDescriptor::~ParcelFileDescriptor() = default;
+
+status_t ParcelFileDescriptor::writeToParcel(Parcel* parcel) const {
+    return parcel->writeDupParcelFileDescriptor(mFd.get());
+}
+
+status_t ParcelFileDescriptor::readFromParcel(const Parcel* parcel) {
+    return parcel->readUniqueParcelFileDescriptor(&mFd);
+}
+
+} // namespace os
+} // namespace android
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
index a503be8..a4c28ad 100644
--- a/libs/binder/PermissionCache.cpp
+++ b/libs/binder/PermissionCache.cpp
@@ -75,7 +75,7 @@
 }
 
 bool PermissionCache::checkCallingPermission(const String16& permission) {
-    return PermissionCache::checkCallingPermission(permission, NULL, NULL);
+    return PermissionCache::checkCallingPermission(permission, nullptr, nullptr);
 }
 
 bool PermissionCache::checkCallingPermission(
diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp
index 96df33c..34b2ca5 100644
--- a/libs/binder/PermissionController.cpp
+++ b/libs/binder/PermissionController.cpp
@@ -41,7 +41,7 @@
                 ALOGI("Waiting for permission service");
             } else if ((uptimeMillis() - startTime) > 10000) {
                 ALOGW("Waiting too long for permission service, giving up");
-                service = NULL;
+                service = nullptr;
                 break;
             }
             sleep(1);
@@ -56,13 +56,13 @@
 bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid)
 {
     sp<IPermissionController> service = getService();
-    return service != NULL ? service->checkPermission(permission, pid, uid) : false;
+    return service != nullptr ? service->checkPermission(permission, pid, uid) : false;
 }
 
 int32_t PermissionController::noteOp(const String16& op, int32_t uid, const String16& packageName)
 {
     sp<IPermissionController> service = getService();
-    return service != NULL ? service->noteOp(op, uid, packageName) : MODE_ERRORED;
+    return service != nullptr ? service->noteOp(op, uid, packageName) : MODE_ERRORED;
 }
 
 void PermissionController::getPackagesForUid(const uid_t uid, Vector<String16> &packages)
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index 8939d9c..5cb2033 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -36,7 +36,7 @@
 
     for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
 
-        if (pis != NULL) {
+        if (pis != nullptr) {
             err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states);
             if (err == NO_ERROR) return NO_ERROR; // success
             if (IInterface::asBinder(pis)->isBinderAlive()) return err;
@@ -68,7 +68,7 @@
 
     for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
 
-        if (pis != NULL) {
+        if (pis != nullptr) {
             err = pis->getProcessStatesAndOomScoresFromPids(length,
                     /*in*/ pids, /*out*/ states, /*out*/ scores);
             if (err == NO_ERROR) return NO_ERROR; // success
@@ -93,7 +93,7 @@
 
 void ProcessInfoService::updateBinderLocked() {
     const sp<IServiceManager> sm(defaultServiceManager());
-    if (sm != NULL) {
+    if (sm != nullptr) {
         const String16 name("processinfo");
         mProcessInfoService = interface_cast<IProcessInfoService>(sm->checkService(name));
     }
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index d1c6f84..63f49dd 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -43,6 +43,12 @@
 #define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
 #define DEFAULT_MAX_BINDER_THREADS 15
 
+#ifdef __ANDROID_VNDK__
+const char* kDefaultDriver = "/dev/vndbinder";
+#else
+const char* kDefaultDriver = "/dev/binder";
+#endif
+
 // -------------------------------------------------------------------------
 
 namespace android {
@@ -68,17 +74,17 @@
 sp<ProcessState> ProcessState::self()
 {
     Mutex::Autolock _l(gProcessMutex);
-    if (gProcess != NULL) {
+    if (gProcess != nullptr) {
         return gProcess;
     }
-    gProcess = new ProcessState("/dev/binder");
+    gProcess = new ProcessState(kDefaultDriver);
     return gProcess;
 }
 
 sp<ProcessState> ProcessState::initWithDriver(const char* driver)
 {
     Mutex::Autolock _l(gProcessMutex);
-    if (gProcess != NULL) {
+    if (gProcess != nullptr) {
         // Allow for initWithDriver to be called repeatedly with the same
         // driver.
         if (!strcmp(gProcess->getDriverName().c_str(), driver)) {
@@ -122,18 +128,18 @@
 {
     mLock.lock();
     sp<IBinder> object(
-        mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
+        mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : nullptr);
     mLock.unlock();
     
     //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
     
-    if (object != NULL) return object;
+    if (object != nullptr) return object;
 
     // Don't attempt to retrieve contexts if we manage them
     if (mManagesContexts) {
         ALOGE("getContextObject(%s) failed, but we manage the contexts!\n",
             String8(name).string());
-        return NULL;
+        return nullptr;
     }
     
     IPCThreadState* ipc = IPCThreadState::self();
@@ -150,7 +156,7 @@
     
     ipc->flushCommands();
     
-    if (object != NULL) setContextObject(object, name);
+    if (object != nullptr) setContextObject(object, name);
     return object;
 }
 
@@ -175,13 +181,25 @@
         mBinderContextCheckFunc = checkFunc;
         mBinderContextUserData = userData;
 
-        int dummy = 0;
-        status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+        flat_binder_object obj {
+            .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
+        };
+
+        status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
+
+        // fallback to original method
+        if (result != 0) {
+            android_errorWriteLog(0x534e4554, "121035042");
+
+            int dummy = 0;
+            result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+        }
+
         if (result == 0) {
             mManagesContexts = true;
         } else if (result == -1) {
-            mBinderContextCheckFunc = NULL;
-            mBinderContextUserData = NULL;
+            mBinderContextCheckFunc = nullptr;
+            mBinderContextUserData = nullptr;
             ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
         }
     }
@@ -196,18 +214,9 @@
 // already be invalid.
 ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf)
 {
-    // TODO: remove these when they are defined by bionic's binder.h
-    struct binder_node_debug_info {
-        binder_uintptr_t ptr;
-        binder_uintptr_t cookie;
-        __u32 has_strong_ref;
-        __u32 has_weak_ref;
-    };
-#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
-
     binder_node_debug_info info = {};
 
-    uintptr_t* end = buf ? buf + buf_count : NULL;
+    uintptr_t* end = buf ? buf + buf_count : nullptr;
     size_t count = 0;
 
     do {
@@ -228,15 +237,21 @@
     return count;
 }
 
+void ProcessState::setCallRestriction(CallRestriction restriction) {
+    LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull(), "Call restrictions must be set before the threadpool is started.");
+
+    mCallRestriction = restriction;
+}
+
 ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
 {
     const size_t N=mHandleToObject.size();
     if (N <= (size_t)handle) {
         handle_entry e;
-        e.binder = NULL;
-        e.refs = NULL;
+        e.binder = nullptr;
+        e.refs = nullptr;
         status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
-        if (err < NO_ERROR) return NULL;
+        if (err < NO_ERROR) return nullptr;
     }
     return &mHandleToObject.editItemAt(handle);
 }
@@ -249,12 +264,12 @@
 
     handle_entry* e = lookupHandleLocked(handle);
 
-    if (e != NULL) {
+    if (e != nullptr) {
         // We need to create a new BpBinder if there isn't currently one, OR we
         // are unable to acquire a weak reference on this current one.  See comment
         // in getWeakProxyForHandle() for more info about this.
         IBinder* b = e->binder;
-        if (b == NULL || !e->refs->attemptIncWeak(this)) {
+        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
             if (handle == 0) {
                 // Special case for context manager...
                 // The context manager is the only object for which we create
@@ -277,9 +292,9 @@
 
                 Parcel data;
                 status_t status = IPCThreadState::self()->transact(
-                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
+                        0, IBinder::PING_TRANSACTION, data, nullptr, 0);
                 if (status == DEAD_OBJECT)
-                   return NULL;
+                   return nullptr;
             }
 
             b = BpBinder::create(handle);
@@ -306,7 +321,7 @@
 
     handle_entry* e = lookupHandleLocked(handle);
 
-    if (e != NULL) {        
+    if (e != nullptr) {        
         // We need to create a new BpBinder if there isn't currently one, OR we
         // are unable to acquire a weak reference on this current one.  The
         // attemptIncWeak() is safe because we know the BpBinder destructor will always
@@ -315,7 +330,7 @@
         // releasing a reference on this BpBinder, and a new reference on its handle
         // arriving from the driver.
         IBinder* b = e->binder;
-        if (b == NULL || !e->refs->attemptIncWeak(this)) {
+        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
             b = BpBinder::create(handle);
             result = b;
             e->binder = b;
@@ -338,7 +353,7 @@
     // This handle may have already been replaced with a new BpBinder
     // (if someone failed the AttemptIncWeak() above); we don't want
     // to overwrite it.
-    if (e && e->binder == binder) e->binder = NULL;
+    if (e && e->binder == binder) e->binder = nullptr;
 }
 
 String8 ProcessState::makeBinderThreadName() {
@@ -416,14 +431,15 @@
     , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
     , mStarvationStartTimeMs(0)
     , mManagesContexts(false)
-    , mBinderContextCheckFunc(NULL)
-    , mBinderContextUserData(NULL)
+    , mBinderContextCheckFunc(nullptr)
+    , mBinderContextUserData(nullptr)
     , mThreadPoolStarted(false)
     , mThreadPoolSeq(1)
+    , mCallRestriction(CallRestriction::NONE)
 {
     if (mDriverFD >= 0) {
         // mmap the binder, providing a chunk of virtual address space to receive transactions.
-        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
         if (mVMStart == MAP_FAILED) {
             // *sigh*
             ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index d6d0340..bd0e6f9 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -75,21 +75,6 @@
 Mutex& gProcessMutex = *new Mutex;
 sp<ProcessState> gProcess;
 
-class LibBinderIPCtStatics
-{
-public:
-    LibBinderIPCtStatics()
-    {
-    }
-    
-    ~LibBinderIPCtStatics()
-    {
-        IPCThreadState::shutdown();
-    }
-};
-
-static LibBinderIPCtStatics gIPCStatics;
-
 // ------------ IServiceManager.cpp
 
 Mutex gDefaultServiceManagerLock;
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index fe0e592..0ad99ce 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -24,11 +24,17 @@
 }
 
 Status Status::fromExceptionCode(int32_t exceptionCode) {
+    if (exceptionCode == EX_TRANSACTION_FAILED) {
+        return Status(exceptionCode, FAILED_TRANSACTION);
+    }
     return Status(exceptionCode, OK);
 }
 
 Status Status::fromExceptionCode(int32_t exceptionCode,
                                  const String8& message) {
+    if (exceptionCode == EX_TRANSACTION_FAILED) {
+        return Status(exceptionCode, FAILED_TRANSACTION, message);
+    }
     return Status(exceptionCode, OK, message);
 }
 
@@ -57,6 +63,26 @@
     return ret;
 }
 
+std::string Status::exceptionToString(int32_t exceptionCode) {
+    switch (exceptionCode) {
+        #define EXCEPTION_TO_CASE(EXCEPTION) case EXCEPTION: return #EXCEPTION;
+        EXCEPTION_TO_CASE(EX_NONE)
+        EXCEPTION_TO_CASE(EX_SECURITY)
+        EXCEPTION_TO_CASE(EX_BAD_PARCELABLE)
+        EXCEPTION_TO_CASE(EX_ILLEGAL_ARGUMENT)
+        EXCEPTION_TO_CASE(EX_NULL_POINTER)
+        EXCEPTION_TO_CASE(EX_ILLEGAL_STATE)
+        EXCEPTION_TO_CASE(EX_NETWORK_MAIN_THREAD)
+        EXCEPTION_TO_CASE(EX_UNSUPPORTED_OPERATION)
+        EXCEPTION_TO_CASE(EX_SERVICE_SPECIFIC)
+        EXCEPTION_TO_CASE(EX_PARCELABLE)
+        EXCEPTION_TO_CASE(EX_HAS_REPLY_HEADER)
+        EXCEPTION_TO_CASE(EX_TRANSACTION_FAILED)
+        #undef EXCEPTION_TO_CASE
+        default: return std::to_string(exceptionCode);
+    }
+}
+
 Status::Status(int32_t exceptionCode, int32_t errorCode)
     : mException(exceptionCode),
       mErrorCode(errorCode) {}
@@ -185,7 +211,7 @@
 
 void Status::setException(int32_t ex, const String8& message) {
     mException = ex;
-    mErrorCode = NO_ERROR;  // an exception, not a transaction failure.
+    mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
     mMessage.setTo(message);
 }
 
@@ -205,7 +231,7 @@
     if (mException == EX_NONE) {
         ret.append("No error");
     } else {
-        ret.appendFormat("Status(%d): '", mException);
+        ret.appendFormat("Status(%d, %s): '", mException, exceptionToString(mException).c_str());
         if (mException == EX_SERVICE_SPECIFIC ||
             mException == EX_TRANSACTION_FAILED) {
             ret.appendFormat("%d: ", mErrorCode);
diff --git a/libs/binder/Value.cpp b/libs/binder/Value.cpp
index 85cd739..19c57ba 100644
--- a/libs/binder/Value.cpp
+++ b/libs/binder/Value.cpp
@@ -97,7 +97,7 @@
 template<typename T> class Value::Content : public Value::ContentBase {
 public:
     Content() = default;
-    Content(const T & value) : mValue(value) { }
+    explicit Content(const T & value) : mValue(value) { }
 
     virtual ~Content() = default;
 
@@ -143,12 +143,12 @@
 
 // ====================================================================
 
-Value::Value() : mContent(NULL)
+Value::Value() : mContent(nullptr)
 {
 }
 
 Value::Value(const Value& value)
-    : mContent(value.mContent ? value.mContent->clone() : NULL)
+    : mContent(value.mContent ? value.mContent->clone() : nullptr)
 {
 }
 
@@ -165,8 +165,8 @@
         return true;
     }
 
-    if ( (lhs.mContent == NULL)
-      || (rhs.mContent == NULL)
+    if ( (lhs.mContent == nullptr)
+      || (rhs.mContent == nullptr)
     ) {
         return false;
     }
@@ -186,25 +186,25 @@
         delete mContent;
         mContent = rhs.mContent
             ? rhs.mContent->clone()
-            : NULL;
+            : nullptr;
     }
     return *this;
 }
 
 bool Value::empty() const
 {
-    return mContent == NULL;
+    return mContent == nullptr;
 }
 
 void Value::clear()
 {
     delete mContent;
-    mContent = NULL;
+    mContent = nullptr;
 }
 
 int32_t Value::parcelType() const
 {
-    const void* t_info(mContent ? mContent->type_ptr() : NULL);
+    const void* t_info(mContent ? mContent->type_ptr() : nullptr);
 
     if (t_info == internal_type_ptr<bool>()) return VAL_BOOLEAN;
     if (t_info == internal_type_ptr<uint8_t>()) return VAL_BYTE;
@@ -229,7 +229,7 @@
 #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO
 const std::type_info& Value::type() const
 {
-    return mContent != NULL
+    return mContent != nullptr
         ? mContent->type()
         : typeid(void);
 }
@@ -306,7 +306,7 @@
 
 #define BEGIN_HANDLE_WRITE()                                                                      \
     do {                                                                                          \
-        const void* t_info(mContent?mContent->type_ptr():NULL);                                   \
+        const void* t_info(mContent?mContent->type_ptr():nullptr);                                \
         if (false) { }
 #define HANDLE_WRITE_TYPE(T, TYPEVAL, TYPEMETHOD)                                                 \
     else if (t_info == internal_type_ptr<T>()) {                                                  \
@@ -381,7 +381,7 @@
     int32_t value_type = VAL_NULL;
 
     delete mContent;
-    mContent = NULL;
+    mContent = nullptr;
 
     RETURN_IF_FAILED(parcel->readInt32(&value_type));
 
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 5b66b92..a7a7292 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -54,4 +54,37 @@
 
     long getVersionCodeForPackage(in String packageName);
 
+    /**
+     * Return if each app, identified by its package name allows its audio to be recorded.
+     * Unknown packages are mapped to false.
+     */
+    boolean[] isAudioPlaybackCaptureAllowed(in @utf8InCpp String[] packageNames);
+
+    /*  ApplicationInfo.isSystemApp() == true */
+    const int LOCATION_SYSTEM = 0x1;
+    /*  ApplicationInfo.isVendor() == true */
+    const int LOCATION_VENDOR = 0x2;
+    /*  ApplicationInfo.isProduct() == true */
+    const int LOCATION_PRODUCT = 0x4;
+
+    /**
+     * Returns a set of bitflags about package location.
+     * LOCATION_SYSTEM: getApplicationInfo(packageName).isSystemApp()
+     * LOCATION_VENDOR: getApplicationInfo(packageName).isVendor()
+     * LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct()
+     */
+    int getLocationFlags(in @utf8InCpp String packageName);
+
+    /**
+     * Returns the target SDK version for the given package.
+     * Unknown packages will cause the call to fail. The caller must check the
+     * returned Status before using the result of this function.
+     */
+    int getTargetSdkVersionForPackage(in String packageName);
+
+    /**
+     * Returns the name of module metadata package, or empty string if device doesn't have such
+     * package.
+     */
+    @utf8InCpp String getModuleMetadataPackageName();
 }
diff --git a/libs/binder/aidl/android/content/pm/OWNERS b/libs/binder/aidl/android/content/pm/OWNERS
new file mode 100644
index 0000000..b99ca09
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/OWNERS
@@ -0,0 +1,4 @@
+narayan@google.com
+patb@google.com
+svetoslavganov@google.com
+toddke@google.com
\ No newline at end of file
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index b8db091..5f324c7 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -31,6 +31,8 @@
 public:
 
     enum {
+        // Flag for registerUidObserver: report uid state changed
+        UID_OBSERVER_PROCSTATE = 1<<0,
         // Flag for registerUidObserver: report uid gone
         UID_OBSERVER_GONE = 1<<1,
         // Flag for registerUidObserver: report uid has become idle
@@ -40,8 +42,29 @@
     };
 
     enum {
-        // Not a real process state
-        PROCESS_STATE_UNKNOWN = -1
+        PROCESS_STATE_UNKNOWN = -1,
+        PROCESS_STATE_PERSISTENT = 0,
+        PROCESS_STATE_PERSISTENT_UI = 1,
+        PROCESS_STATE_TOP = 2,
+        PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3,
+        PROCESS_STATE_BOUND_TOP = 4,
+        PROCESS_STATE_FOREGROUND_SERVICE = 5,
+        PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6,
+        PROCESS_STATE_IMPORTANT_FOREGROUND = 7,
+        PROCESS_STATE_IMPORTANT_BACKGROUND = 8,
+        PROCESS_STATE_TRANSIENT_BACKGROUND = 9,
+        PROCESS_STATE_BACKUP = 10,
+        PROCESS_STATE_SERVICE = 11,
+        PROCESS_STATE_RECEIVER = 12,
+        PROCESS_STATE_TOP_SLEEPING = 13,
+        PROCESS_STATE_HEAVY_WEIGHT = 14,
+        PROCESS_STATE_HOME = 15,
+        PROCESS_STATE_LAST_ACTIVITY = 16,
+        PROCESS_STATE_CACHED_ACTIVITY = 17,
+        PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18,
+        PROCESS_STATE_CACHED_RECENT = 19,
+        PROCESS_STATE_CACHED_EMPTY = 20,
+        PROCESS_STATE_NONEXISTENT = 21,
     };
 
     ActivityManager();
@@ -53,8 +76,10 @@
                              const String16& callingPackage);
     void unregisterUidObserver(const sp<IUidObserver>& observer);
     bool isUidActive(const uid_t uid, const String16& callingPackage);
+    int getUidProcessState(const uid_t uid, const String16& callingPackage);
 
-    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
+  status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
     status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
 
 private:
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index c5b57c7..17493b4 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -95,11 +95,27 @@
         OP_USE_FINGERPRINT = 55,
         OP_BODY_SENSORS = 56,
         OP_AUDIO_ACCESSIBILITY_VOLUME = 64,
+        OP_READ_PHONE_NUMBERS = 65,
+        OP_REQUEST_INSTALL_PACKAGES = 66,
+        OP_PICTURE_IN_PICTURE = 67,
+        OP_INSTANT_APP_START_FOREGROUND = 68,
+        OP_ANSWER_PHONE_CALLS = 69,
+        OP_RUN_ANY_IN_BACKGROUND = 70,
+        OP_CHANGE_WIFI_STATE = 71,
+        OP_REQUEST_DELETE_PACKAGES = 72,
+        OP_BIND_ACCESSIBILITY_SERVICE = 73,
+        OP_ACCEPT_HANDOVER = 74,
+        OP_MANAGE_IPSEC_TUNNELS = 75,
+        OP_START_FOREGROUND = 76,
+        OP_BLUETOOTH_SCAN = 77,
+        OP_USE_BIOMETRIC = 78,
     };
 
     AppOpsManager();
 
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
+            const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
             bool startIfModeDefault);
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 3404881..cf3ef84 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -34,19 +34,22 @@
     virtual status_t    pingBinder();
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    transact(   uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
                                     uint32_t flags = 0);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
-                                    void* cookie = NULL,
+                                    void* cookie = nullptr,
                                     uint32_t flags = 0);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
-                                        void* cookie = NULL,
+                                        void* cookie = nullptr,
                                         uint32_t flags = 0,
-                                        wp<DeathRecipient>* outRecipient = NULL);
+                                        wp<DeathRecipient>* outRecipient = nullptr);
 
     virtual void        attachObject(   const void* objectID,
                                         void* object,
@@ -57,9 +60,14 @@
 
     virtual BBinder*    localBinder();
 
+    bool                isRequestingSid();
+    // This must be called before the object is sent to another process. Not thread safe.
+    void                setRequestingSid(bool requestSid);
+
 protected:
     virtual             ~BBinder();
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
@@ -71,6 +79,8 @@
 
     class Extras;
 
+    Extras*             getOrCreateExtras();
+
     std::atomic<Extras*> mExtras;
             void*       mReserved0;
 };
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 8bd297b..1d4f881 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -41,18 +41,22 @@
     virtual status_t    pingBinder();
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    transact(   uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
                                     uint32_t flags = 0);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
-                                    void* cookie = NULL,
+                                    void* cookie = nullptr,
                                     uint32_t flags = 0);
+
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
-                                        void* cookie = NULL,
+                                        void* cookie = nullptr,
                                         uint32_t flags = 0,
-                                        wp<DeathRecipient>* outRecipient = NULL);
+                                        wp<DeathRecipient>* outRecipient = nullptr);
 
     virtual void        attachObject(   const void* objectID,
                                         void* object,
diff --git a/libs/binder/include/binder/BufferedTextOutput.h b/libs/binder/include/binder/BufferedTextOutput.h
index 9a7c43b..feae93d 100644
--- a/libs/binder/include/binder/BufferedTextOutput.h
+++ b/libs/binder/include/binder/BufferedTextOutput.h
@@ -32,7 +32,7 @@
         MULTITHREADED = 0x0001
     };
     
-                        BufferedTextOutput(uint32_t flags = 0);
+    explicit            BufferedTextOutput(uint32_t flags = 0);
     virtual             ~BufferedTextOutput();
     
     virtual status_t    print(const char* txt, size_t len);
diff --git a/libs/binder/include/binder/Debug.h b/libs/binder/include/binder/Debug.h
index be0266c..58e2b32 100644
--- a/libs/binder/include/binder/Debug.h
+++ b/libs/binder/include/binder/Debug.h
@@ -31,12 +31,12 @@
 typedef void (*debugPrintFunc)(void* cookie, const char* txt);
 
 void printTypeCode(uint32_t typeCode,
-    debugPrintFunc func = 0, void* cookie = 0);
+    debugPrintFunc func = nullptr, void* cookie = nullptr);
 
 void printHexData(int32_t indent, const void *buf, size_t length,
     size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
     size_t alignment=0, bool cArrayStyle=false,
-    debugPrintFunc func = 0, void* cookie = 0);
+    debugPrintFunc func = nullptr, void* cookie = nullptr);
 
 
 ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf);
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index f34969b..6abc071 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -38,12 +38,14 @@
                                      const String16& callingPackage) = 0;
     virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
     virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
+    virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0;
 
     enum {
         OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         REGISTER_UID_OBSERVER_TRANSACTION,
         UNREGISTER_UID_OBSERVER_TRANSACTION,
-        IS_UID_ACTIVE_TRANSACTION
+        IS_UID_ACTIVE_TRANSACTION,
+        GET_UID_PROCESS_STATE_TRANSACTION
     };
 };
 
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index e5b12a9..b500219 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -43,6 +43,7 @@
 class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index f0c5e17..3dbd0d9 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -43,6 +43,8 @@
     virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
     virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0;
     virtual int32_t permissionToOpCode(const String16& permission) = 0;
+    virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
+            const String16& packageName) = 0;
 
     enum {
         CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -53,6 +55,7 @@
         STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
         GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
         PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
+        CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
     };
 
     enum {
@@ -67,6 +70,7 @@
 class BnAppOpsService : public BnInterface<IAppOpsService>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index 59e806c..48da865 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -68,6 +68,7 @@
 class BnBatteryStats : public BnInterface<IBatteryStats>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 2e62957..aa44285 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -47,7 +47,7 @@
  * (method calls, property get and set) is down through a low-level
  * protocol implemented on top of the transact() API.
  */
-class IBinder : public virtual RefBase
+class [[clang::lto_visibility_public]] IBinder : public virtual RefBase
 {
 public:
     enum {
@@ -86,6 +86,7 @@
                                          Vector<String16>& args, const sp<IShellCallback>& callback,
                                          const sp<IResultReceiver>& resultReceiver);
 
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t        transact(   uint32_t code,
                                         const Parcel& data,
                                         Parcel* reply,
@@ -131,8 +132,9 @@
      * (Nor should you need to, as there is nothing useful you can
      * directly do with it now that it has passed on.)
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
-                                        void* cookie = NULL,
+                                        void* cookie = nullptr,
                                         uint32_t flags = 0) = 0;
 
     /**
@@ -141,21 +143,45 @@
      * dies.  The @a cookie is optional.  If non-NULL, you can
      * supply a NULL @a recipient, and the recipient previously
      * added with that cookie will be unlinked.
+     *
+     * If the binder is dead, this will return DEAD_OBJECT. Deleting
+     * the object will also unlink all death recipients.
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
-                                            void* cookie = NULL,
+                                            void* cookie = nullptr,
                                             uint32_t flags = 0,
-                                            wp<DeathRecipient>* outRecipient = NULL) = 0;
+                                            wp<DeathRecipient>* outRecipient = nullptr) = 0;
 
     virtual bool            checkSubclass(const void* subclassID) const;
 
     typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
 
+    /**
+     * This object is attached for the lifetime of this binder object. When
+     * this binder object is destructed, the cleanup function of all attached
+     * objects are invoked with their respective objectID, object, and
+     * cleanupCookie. Access to these APIs can be made from multiple threads,
+     * but calls from different threads are allowed to be interleaved.
+     */
     virtual void            attachObject(   const void* objectID,
                                             void* object,
                                             void* cleanupCookie,
                                             object_cleanup_func func) = 0;
+    /**
+     * Returns object attached with attachObject.
+     */
     virtual void*           findObject(const void* objectID) const = 0;
+    /**
+     * WARNING: this API does not call the cleanup function for legacy reasons.
+     * It also does not return void* for legacy reasons. If you need to detach
+     * an object and destroy it, there are two options:
+     * - if you can, don't call detachObject and instead wait for the destructor
+     *   to clean it up.
+     * - manually retrieve and destruct the object (if multiple of your threads
+     *   are accessing these APIs, you must guarantee that attachObject isn't
+     *   called after findObject and before detachObject is called).
+     */
     virtual void            detachObject(const void* objectID) = 0;
 
     virtual BBinder*        localBinder();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 0f1fe5b..0d30560 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -54,6 +54,7 @@
     virtual const String16&     getInterfaceDescriptor() const;
 
 protected:
+    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
@@ -66,18 +67,25 @@
     explicit                    BpInterface(const sp<IBinder>& remote);
 
 protected:
+    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
 // ----------------------------------------------------------------------
 
 #define DECLARE_META_INTERFACE(INTERFACE)                               \
+public:                                                                 \
     static const ::android::String16 descriptor;                        \
     static ::android::sp<I##INTERFACE> asInterface(                     \
             const ::android::sp<::android::IBinder>& obj);              \
     virtual const ::android::String16& getInterfaceDescriptor() const;  \
     I##INTERFACE();                                                     \
     virtual ~I##INTERFACE();                                            \
+    static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl);     \
+    static const std::unique_ptr<I##INTERFACE>& getDefaultImpl();       \
+private:                                                                \
+    static std::unique_ptr<I##INTERFACE> default_impl;                  \
+public:                                                                 \
 
 
 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
@@ -90,22 +98,37 @@
             const ::android::sp<::android::IBinder>& obj)               \
     {                                                                   \
         ::android::sp<I##INTERFACE> intr;                               \
-        if (obj != NULL) {                                              \
+        if (obj != nullptr) {                                           \
             intr = static_cast<I##INTERFACE*>(                          \
                 obj->queryLocalInterface(                               \
                         I##INTERFACE::descriptor).get());               \
-            if (intr == NULL) {                                         \
+            if (intr == nullptr) {                                      \
                 intr = new Bp##INTERFACE(obj);                          \
             }                                                           \
         }                                                               \
         return intr;                                                    \
     }                                                                   \
+    std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl;           \
+    bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
+    {                                                                   \
+        if (!I##INTERFACE::default_impl && impl) {                      \
+            I##INTERFACE::default_impl = std::move(impl);               \
+            return true;                                                \
+        }                                                               \
+        return false;                                                   \
+    }                                                                   \
+    const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
+    {                                                                   \
+        return I##INTERFACE::default_impl;                              \
+    }                                                                   \
     I##INTERFACE::I##INTERFACE() { }                                    \
     I##INTERFACE::~I##INTERFACE() { }                                   \
 
 
 #define CHECK_INTERFACE(interface, data, reply)                         \
-    if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }     \
+    do {                                                                \
+      if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }   \
+    } while (false)                                                     \
 
 
 // ----------------------------------------------------------------------
@@ -116,7 +139,7 @@
         const String16& _descriptor)
 {
     if (_descriptor == INTERFACE::descriptor) return this;
-    return NULL;
+    return nullptr;
 }
 
 template<typename INTERFACE>
@@ -142,7 +165,7 @@
 {
     return remote();
 }
-    
+
 // ----------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 15a104f..071946f 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -43,7 +43,7 @@
     virtual void*       getBase() const = 0;
     virtual size_t      getSize() const = 0;
     virtual uint32_t    getFlags() const = 0;
-    virtual uint32_t    getOffset() const = 0;
+    virtual off_t       getOffset() const = 0;
 
     // these are there just for backward source compatibility
     int32_t heapID() const { return getHeapID(); }
@@ -54,7 +54,8 @@
 class BnMemoryHeap : public BnInterface<IMemoryHeap>
 {
 public:
-    virtual status_t onTransact( 
+    // NOLINTNEXTLINE(google-default-arguments)
+    virtual status_t onTransact(
             uint32_t code,
             const Parcel& data,
             Parcel* reply,
@@ -72,7 +73,8 @@
 public:
     DECLARE_META_INTERFACE(Memory)
 
-    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
+    // NOLINTNEXTLINE(google-default-arguments)
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0;
 
     // helpers
     void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
@@ -84,6 +86,7 @@
 class BnMemory : public BnInterface<IMemory>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t onTransact(
             uint32_t code,
             const Parcel& data,
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index c1d9a9a..614b0b3 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -29,6 +29,8 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+class IPCThreadStateBase;
+
 class IPCThreadState
 {
 public:
@@ -40,15 +42,34 @@
             status_t            clearLastError();
 
             pid_t               getCallingPid() const;
+            // nullptr if unavailable
+            //
+            // this can't be restored once it's cleared, and it does not return the
+            // context of the current process when not in a binder call.
+            const char*         getCallingSid() const;
             uid_t               getCallingUid() const;
 
             void                setStrictModePolicy(int32_t policy);
             int32_t             getStrictModePolicy() const;
 
+            // See Binder#setCallingWorkSourceUid in Binder.java.
+            int64_t             setCallingWorkSourceUid(uid_t uid);
+            // Internal only. Use setCallingWorkSourceUid(uid) instead.
+            int64_t             setCallingWorkSourceUidWithoutPropagation(uid_t uid);
+            // See Binder#getCallingWorkSourceUid in Binder.java.
+            uid_t               getCallingWorkSourceUid() const;
+            // See Binder#clearCallingWorkSource in Binder.java.
+            int64_t             clearCallingWorkSource();
+            // See Binder#restoreCallingWorkSource in Binder.java.
+            void                restoreCallingWorkSource(int64_t token);
+            void                clearPropagateWorkSource();
+            bool                shouldPropagateWorkSource() const;
+
             void                setLastTransactionBinderFlags(int32_t flags);
             int32_t             getLastTransactionBinderFlags() const;
 
             int64_t             clearCallingIdentity();
+            // Restores PID/UID (not SID)
             void                restoreCallingIdentity(int64_t token);
             
             int                 setupPolling(int* fd);
@@ -89,13 +110,47 @@
             // the maximum number of binder threads threads allowed for this process.
             void                blockUntilThreadAvailable();
 
+
+            // Is this thread currently serving a binder call. This method
+            // returns true if while traversing backwards from the function call
+            // stack for this thread, we encounter a function serving a binder
+            // call before encountering a hwbinder call / hitting the end of the
+            // call stack.
+            // Eg: If thread T1 went through the following call pattern
+            //     1) T1 receives and executes hwbinder call H1.
+            //     2) While handling H1, T1 makes binder call B1.
+            //     3) The handler of B1, calls into T1 with a callback B2.
+            // If isServingCall() is called during H1 before 3), this method
+            // will return false, else true.
+            //
+            //  ----
+            // | B2 | ---> While callback B2 is being handled, during 3).
+            //  ----
+            // | H1 | ---> While H1 is being handled.
+            //  ----
+            // Fig: Thread Call stack while handling B2
+            //
+            // This is since after 3), while traversing the thread call stack,
+            // we hit a binder call before a hwbinder call / end of stack. This
+            // method may be typically used to determine whether to use
+            // hardware::IPCThreadState methods or IPCThreadState methods to
+            // infer information about thread state.
+            bool                isServingCall() const;
+
+            // The work source represents the UID of the process we should attribute the transaction
+            // to. We use -1 to specify that the work source was not set using #setWorkSource.
+            //
+            // This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java
+            // side.
+            static const int32_t kUnsetWorkSource = -1;
+
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
 
             status_t            sendReply(const Parcel& reply, uint32_t flags);
             status_t            waitForResponse(Parcel *reply,
-                                                status_t *acquireResult=NULL);
+                                                status_t *acquireResult=nullptr);
             status_t            talkWithDriver(bool doReceive=true);
             status_t            writeTransactionData(int32_t cmd,
                                                      uint32_t binderFlags,
@@ -125,9 +180,18 @@
             Parcel              mOut;
             status_t            mLastError;
             pid_t               mCallingPid;
+            const char*         mCallingSid;
             uid_t               mCallingUid;
+            // The UID of the process who is responsible for this transaction.
+            // This is used for resource attribution.
+            int32_t             mWorkSource;
+            // Whether the work source should be propagated.
+            bool                mPropagateWorkSource;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
+            IPCThreadStateBase  *mIPCThreadStateBase;
+
+            ProcessState::CallRestriction mCallRestriction;
 };
 
 }; // namespace android
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 3ec459f..26a1b23 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -56,6 +56,7 @@
 class BnPermissionController : public BnInterface<IPermissionController>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
index e494fba..00b3d89 100644
--- a/libs/binder/include/binder/IResultReceiver.h
+++ b/libs/binder/include/binder/IResultReceiver.h
@@ -41,6 +41,7 @@
 class BnResultReceiver : public BnInterface<IResultReceiver>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 197026d..aeea1a2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -61,6 +61,7 @@
     /**
      * Register a service.
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                 bool allowIsolated = false,
                                 int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
@@ -68,6 +69,7 @@
     /**
      * Return list of all existing services.
      */
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
 
     enum {
@@ -84,9 +86,9 @@
 status_t getService(const String16& name, sp<INTERFACE>* outService)
 {
     const sp<IServiceManager> sm = defaultServiceManager();
-    if (sm != NULL) {
+    if (sm != nullptr) {
         *outService = interface_cast<INTERFACE>(sm->getService(name));
-        if ((*outService) != NULL) return NO_ERROR;
+        if ((*outService) != nullptr) return NO_ERROR;
     }
     return NAME_NOT_FOUND;
 }
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index b47e995..6715678 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -42,6 +42,7 @@
 class BnShellCallback : public BnInterface<IShellCallback>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t    onTransact( uint32_t code,
                                     const Parcel& data,
                                     Parcel* reply,
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
index d81789e..a1f530d 100644
--- a/libs/binder/include/binder/IUidObserver.h
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -34,11 +34,13 @@
     virtual void onUidGone(uid_t uid, bool disabled) = 0;
     virtual void onUidActive(uid_t uid) = 0;
     virtual void onUidIdle(uid_t uid, bool disabled) = 0;
+    virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq) = 0;
 
     enum {
         ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         ON_UID_ACTIVE_TRANSACTION,
-        ON_UID_IDLE_TRANSACTION
+        ON_UID_IDLE_TRANSACTION,
+        ON_UID_STATE_CHANGED_TRANSACTION
     };
 };
 
@@ -47,6 +49,7 @@
 class BnUidObserver : public BnInterface<IUidObserver>
 {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t  onTransact(uint32_t code,
                                  const Parcel& data,
                                  Parcel* reply,
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
index dd5bc3a..c7e7a50 100644
--- a/libs/binder/include/binder/IpPrefix.h
+++ b/libs/binder/include/binder/IpPrefix.h
@@ -74,8 +74,8 @@
 private:
     union InternalUnion {
         InternalUnion() = default;
-        InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { };
-        InternalUnion(const struct in_addr &addr):mInAddr(addr) { };
+        explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { };
+        explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { };
         struct in6_addr mIn6Addr;
         struct in_addr mInAddr;
     } mUnion;
diff --git a/libs/binder/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h
index 60a624c..b483be0 100644
--- a/libs/binder/include/binder/MemoryDealer.h
+++ b/libs/binder/include/binder/MemoryDealer.h
@@ -34,7 +34,7 @@
 class MemoryDealer : public RefBase
 {
 public:
-    MemoryDealer(size_t size, const char* name = 0,
+    explicit MemoryDealer(size_t size, const char* name = nullptr,
             uint32_t flags = 0 /* or bits such as MemoryHeapBase::READ_ONLY */ );
 
     virtual sp<IMemory> allocate(size_t size);
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index ea9b66c..100d784 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -42,17 +42,17 @@
      * maps the memory referenced by fd. but DOESN'T take ownership
      * of the filedescriptor (it makes a copy with dup()
      */
-    MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
+    MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, off_t offset = 0);
 
     /*
      * maps memory from the given device
      */
-    MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
+    explicit MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
 
     /*
      * maps memory from ashmem, with the given name for debugging
      */
-    MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
+    explicit MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = nullptr);
 
     virtual ~MemoryHeapBase();
 
@@ -64,7 +64,7 @@
 
     virtual size_t      getSize() const;
     virtual uint32_t    getFlags() const;
-    virtual uint32_t    getOffset() const;
+            off_t       getOffset() const override;
 
     const char*         getDevice() const;
 
@@ -74,7 +74,7 @@
     /* this is only needed as a workaround, use only if you know
      * what you are doing */
     status_t setDevice(const char* device) {
-        if (mDevice == 0)
+        if (mDevice == nullptr)
             mDevice = device;
         return mDevice ? NO_ERROR : ALREADY_EXISTS;
     }
@@ -82,11 +82,11 @@
 protected:
             MemoryHeapBase();
     // init() takes ownership of fd
-    status_t init(int fd, void *base, int size,
-            int flags = 0, const char* device = NULL);
+    status_t init(int fd, void *base, size_t size,
+            int flags = 0, const char* device = nullptr);
 
 private:
-    status_t mapfd(int fd, size_t size, uint32_t offset = 0);
+    status_t mapfd(int fd, size_t size, off_t offset = 0);
 
     int         mFD;
     size_t      mSize;
@@ -94,7 +94,7 @@
     uint32_t    mFlags;
     const char* mDevice;
     bool        mNeedUnmap;
-    uint32_t    mOffset;
+    off_t       mOffset;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index dede78f..e5219a5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -20,6 +20,8 @@
 #include <string>
 #include <vector>
 
+#include <linux/android/binder.h>
+
 #include <android-base/unique_fd.h>
 #include <cutils/native_handle.h>
 #include <utils/Errors.h>
@@ -27,7 +29,6 @@
 #include <utils/String16.h>
 #include <utils/Vector.h>
 #include <utils/Flattenable.h>
-#include <linux/android/binder.h>
 
 #include <binder/IInterface.h>
 #include <binder/Parcelable.h>
@@ -91,7 +92,7 @@
     // IPCThreadState, which as an optimization may optionally be
     // passed in.
     bool                enforceInterface(const String16& interface,
-                                         IPCThreadState* threadState = NULL) const;
+                                         IPCThreadState* threadState = nullptr) const;
     bool                checkInterface(IBinder*) const;
 
     void                freeData();
@@ -139,6 +140,8 @@
     status_t            writeInt32Vector(const std::vector<int32_t>& val);
     status_t            writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val);
     status_t            writeInt64Vector(const std::vector<int64_t>& val);
+    status_t            writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val);
+    status_t            writeUint64Vector(const std::vector<uint64_t>& val);
     status_t            writeFloatVector(const std::unique_ptr<std::vector<float>>& val);
     status_t            writeFloatVector(const std::vector<float>& val);
     status_t            writeDoubleVector(const std::unique_ptr<std::vector<double>>& val);
@@ -205,6 +208,10 @@
     // The Parcel does not take ownership of the given fd unless you ask it to.
     status_t            writeParcelFileDescriptor(int fd, bool takeOwnership = false);
 
+    // Place a Java "parcel file descriptor" into the parcel.  A dup of the fd is made, which will
+    // be closed once the parcel is destroyed.
+    status_t            writeDupParcelFileDescriptor(int fd);
+
     // Place a file descriptor into the parcel.  This will not affect the
     // semantics of the smart file descriptor. A new descriptor will be
     // created, and will be closed when the parcel is destroyed.
@@ -309,6 +316,8 @@
     status_t            readInt32Vector(std::vector<int32_t>* val) const;
     status_t            readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const;
     status_t            readInt64Vector(std::vector<int64_t>* val) const;
+    status_t            readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const;
+    status_t            readUint64Vector(std::vector<uint64_t>* val) const;
     status_t            readFloatVector(std::unique_ptr<std::vector<float>>* val) const;
     status_t            readFloatVector(std::vector<float>* val) const;
     status_t            readDoubleVector(std::unique_ptr<std::vector<double>>* val) const;
@@ -364,6 +373,9 @@
     status_t            readUniqueFileDescriptor(
                             base::unique_fd* val) const;
 
+    // Retrieve a Java "parcel file descriptor" from the parcel.
+    status_t            readUniqueParcelFileDescriptor(base::unique_fd* val) const;
+
 
     // Retrieve a vector of smart file descriptors from the parcel.
     status_t            readUniqueFileDescriptorVector(
@@ -384,6 +396,12 @@
     static size_t       getGlobalAllocSize();
     static size_t       getGlobalAllocCount();
 
+    bool                replaceCallingWorkSourceUid(uid_t uid);
+    // Returns the work source provided by the caller. This can only be trusted for trusted calling
+    // uid.
+    uid_t               readCallingWorkSourceUid();
+    void                readRequestHeaders() const;
+
 private:
     typedef void        (*release_func)(Parcel* parcel,
                                         const uint8_t* data, size_t dataSize,
@@ -418,6 +436,7 @@
     void                initState();
     void                scanForFds() const;
     status_t            validateReadData(size_t len) const;
+    void                updateWorkSourceRequestHeaderPosition() const;
                         
     template<class T>
     status_t            readAligned(T *pArg) const;
@@ -466,6 +485,9 @@
     mutable size_t      mNextObjectHint;
     mutable bool        mObjectsSorted;
 
+    mutable bool        mRequestHeaderPresent;
+    mutable size_t      mWorkSourceRequestHeaderPosition;
+
     mutable bool        mFdsKnown;
     mutable bool        mHasFds;
     bool                mAllowFds;
@@ -547,7 +569,7 @@
         friend class Parcel;
     public:
         inline const void* data() const { return mData; }
-        inline void* mutableData() { return isMutable() ? mData : NULL; }
+        inline void* mutableData() { return isMutable() ? mData : nullptr; }
     };
 
     class WritableBlob : public Blob {
@@ -587,7 +609,7 @@
     }
     if (size) {
         void* buffer = writeInplace(size);
-        if (buffer == NULL)
+        if (buffer == nullptr)
             return NO_MEMORY;
         return val.flatten(buffer, size);
     }
@@ -615,7 +637,7 @@
     }
     if (size) {
         void const* buffer = readInplace(size);
-        return buffer == NULL ? NO_MEMORY :
+        return buffer == nullptr ? NO_MEMORY :
                 val.unflatten(buffer, size);
     }
     return NO_ERROR;
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
new file mode 100644
index 0000000..662e56e
--- /dev/null
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PARCEL_FILE_DESCRIPTOR_H_
+#define ANDROID_PARCEL_FILE_DESCRIPTOR_H_
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+/*
+ * C++ implementation of the Java class android.os.ParcelFileDescriptor
+ */
+class ParcelFileDescriptor : public android::Parcelable {
+public:
+    ParcelFileDescriptor();
+    explicit ParcelFileDescriptor(android::base::unique_fd fd);
+    ParcelFileDescriptor(ParcelFileDescriptor&& other) : mFd(std::move(other.mFd)) { }
+    ~ParcelFileDescriptor() override;
+
+    int get() const { return mFd.get(); }
+    android::base::unique_fd release() { return std::move(mFd); }
+    void reset(android::base::unique_fd fd = android::base::unique_fd()) { mFd = std::move(fd); }
+
+    // android::Parcelable override:
+    android::status_t writeToParcel(android::Parcel* parcel) const override;
+    android::status_t readFromParcel(const android::Parcel* parcel) override;
+
+private:
+    android::base::unique_fd mFd;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // ANDROID_OS_PARCEL_FILE_DESCRIPTOR_H_
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index f85c261..224cb36 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -36,9 +36,12 @@
 public:
     static  sp<ProcessState>    self();
     static  sp<ProcessState>    selfOrNull();
+
     /* initWithDriver() can be used to configure libbinder to use
      * a different binder driver dev node. It must be called *before*
-     * any call to ProcessState::self(). /dev/binder remains the default.
+     * any call to ProcessState::self(). The default is /dev/vndbinder
+     * for processes built with the VNDK and /dev/binder for those
+     * which are not.
      */
     static  sp<ProcessState>    initWithDriver(const char *driver);
 
@@ -74,10 +77,22 @@
 
             ssize_t             getKernelReferences(size_t count, uintptr_t* buf);
 
+            enum class CallRestriction {
+                // all calls okay
+                NONE,
+                // log when calls are blocking
+                ERROR_IF_NOT_ONEWAY,
+                // abort process on blocking calls
+                FATAL_IF_NOT_ONEWAY,
+            };
+            // Sets calling restrictions for all transactions in this process. This must be called
+            // before any threads are spawned.
+            void setCallRestriction(CallRestriction restriction);
+
 private:
     friend class IPCThreadState;
     
-                                ProcessState(const char* driver);
+            explicit            ProcessState(const char* driver);
                                 ~ProcessState();
 
                                 ProcessState(const ProcessState& o);
@@ -120,6 +135,8 @@
             String8             mRootDir;
             bool                mThreadPoolStarted;
     volatile int32_t            mThreadPoolSeq;
+
+            CallRestriction     mCallRestriction;
 };
     
 }; // namespace android
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
index 3bfd462..5fa2ff6 100644
--- a/libs/binder/include/binder/SafeInterface.h
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -152,6 +152,12 @@
         return callParcel("writeParcelableVector",
                           [&]() { return parcel->writeParcelableVector(v); });
     }
+    status_t read(const Parcel& parcel, float* f) const {
+        return callParcel("readFloat", [&]() { return parcel.readFloat(f); });
+    }
+    status_t write(Parcel* parcel, float f) const {
+        return callParcel("writeFloat", [&]() { return parcel->writeFloat(f); });
+    }
 
     // Templates to handle integral types. We use a struct template to require that the called
     // function exactly matches the signedness and size of the argument (e.g., the argument isn't
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index c3738f8..7d889b6 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -22,6 +22,7 @@
 
 #include <binder/Parcel.h>
 #include <utils/String8.h>
+#include <string>
 
 namespace android {
 namespace binder {
@@ -97,6 +98,8 @@
 
     static Status fromStatusT(status_t status);
 
+    static std::string exceptionToString(status_t exceptionCode);
+
     Status() = default;
     ~Status() = default;
 
diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
index 851e01f..5b5f766 100644
--- a/libs/binder/include/binder/TextOutput.h
+++ b/libs/binder/include/binder/TextOutput.h
@@ -38,7 +38,7 @@
     
     class Bundle {
     public:
-        inline Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
+        inline explicit Bundle(TextOutput& to) : mTO(to) { to.pushBundle(); }
         inline ~Bundle() { mTO.popBundle(); }
     private:
         TextOutput&     mTO;
@@ -80,7 +80,7 @@
 class TypeCode
 {
 public:
-    inline TypeCode(uint32_t code);
+    inline explicit TypeCode(uint32_t code);
     inline ~TypeCode();
 
     inline uint32_t typeCode() const;
diff --git a/libs/binder/include/binder/Value.h b/libs/binder/include/binder/Value.h
index 4dee3d8..735f40e 100644
--- a/libs/binder/include/binder/Value.h
+++ b/libs/binder/include/binder/Value.h
@@ -74,20 +74,20 @@
     bool operator!=(const Value& rhs) const { return !this->operator==(rhs); }
 
     Value(const Value& value);
-    Value(const bool& value);
-    Value(const int8_t& value);
-    Value(const int32_t& value);
-    Value(const int64_t& value);
-    Value(const double& value);
-    Value(const String16& value);
-    Value(const std::vector<bool>& value);
-    Value(const std::vector<uint8_t>& value);
-    Value(const std::vector<int32_t>& value);
-    Value(const std::vector<int64_t>& value);
-    Value(const std::vector<double>& value);
-    Value(const std::vector<String16>& value);
-    Value(const os::PersistableBundle& value);
-    Value(const binder::Map& value);
+    Value(const bool& value); // NOLINT(google-explicit-constructor)
+    Value(const int8_t& value); // NOLINT(google-explicit-constructor)
+    Value(const int32_t& value); // NOLINT(google-explicit-constructor)
+    Value(const int64_t& value); // NOLINT(google-explicit-constructor)
+    Value(const double& value); // NOLINT(google-explicit-constructor)
+    Value(const String16& value); // NOLINT(google-explicit-constructor)
+    Value(const std::vector<bool>& value); // NOLINT(google-explicit-constructor)
+    Value(const std::vector<uint8_t>& value); // NOLINT(google-explicit-constructor)
+    Value(const std::vector<int32_t>& value); // NOLINT(google-explicit-constructor)
+    Value(const std::vector<int64_t>& value); // NOLINT(google-explicit-constructor)
+    Value(const std::vector<double>& value); // NOLINT(google-explicit-constructor)
+    Value(const std::vector<String16>& value); // NOLINT(google-explicit-constructor)
+    Value(const os::PersistableBundle& value); // NOLINT(google-explicit-constructor)
+    Value(const binder::Map& value); // NOLINT(google-explicit-constructor)
 
     Value& operator=(const Value& rhs);
     Value& operator=(const int8_t& rhs);
@@ -153,8 +153,8 @@
     // String Convenience Adapters
     // ---------------------------
 
-    Value(const String8& value):               Value(String16(value)) { }
-    Value(const ::std::string& value):         Value(String8(value.c_str())) { }
+    explicit Value(const String8& value):               Value(String16(value)) { }
+    explicit Value(const ::std::string& value):         Value(String8(value.c_str())) { }
     void putString(const String8& value)       { return putString(String16(value)); }
     void putString(const ::std::string& value) { return putString(String8(value.c_str())); }
     Value& operator=(const String8& rhs)       { return *this = String16(rhs); }
diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format
new file mode 100644
index 0000000..9a9d936
--- /dev/null
+++ b/libs/binder/ndk/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+AllowShortFunctionsOnASingleLine: Inline
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
new file mode 100644
index 0000000..21bef2e
--- /dev/null
+++ b/libs/binder/ndk/Android.bp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_library {
+    name: "libbinder_ndk",
+    vendor_available: true,
+
+    export_include_dirs: [
+        "include_ndk",
+        "include_apex",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+    srcs: [
+        "ibinder.cpp",
+        "ibinder_jni.cpp",
+        "parcel.cpp",
+        "process.cpp",
+        "status.cpp",
+        "service_manager.cpp",
+    ],
+
+    shared_libs: [
+        "libandroid_runtime_lazy",
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+
+    header_libs: [
+        "jni_headers",
+    ],
+    export_header_lib_headers: [
+        "jni_headers",
+    ],
+
+    version_script: "libbinder_ndk.map.txt",
+    stubs: {
+        symbol_file: "libbinder_ndk.map.txt",
+        versions: ["29"],
+    },
+}
+
+ndk_headers {
+    name: "libbinder_ndk_headers",
+    from: "include_ndk/android",
+    to: "android",
+    srcs: [
+        "include_ndk/android/*.h",
+    ],
+    license: "NOTICE",
+}
+
+ndk_library {
+    name: "libbinder_ndk",
+    symbol_file: "libbinder_ndk.map.txt",
+    first_version: "29",
+}
diff --git a/libs/binder/ndk/NOTICE b/libs/binder/ndk/NOTICE
new file mode 100644
index 0000000..d1ab54c
--- /dev/null
+++ b/libs/binder/ndk/NOTICE
@@ -0,0 +1,189 @@
+
+   Copyright (c) 2018, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
new file mode 100644
index 0000000..bd6886d
--- /dev/null
+++ b/libs/binder/ndk/ibinder.cpp
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_ibinder.h>
+#include "ibinder_internal.h"
+
+#include <android/binder_status.h>
+#include "parcel_internal.h"
+#include "status_internal.h"
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+
+using DeathRecipient = ::android::IBinder::DeathRecipient;
+
+using ::android::IBinder;
+using ::android::Parcel;
+using ::android::sp;
+using ::android::status_t;
+using ::android::String16;
+using ::android::String8;
+using ::android::wp;
+
+namespace ABBinderTag {
+
+static const void* kId = "ABBinder";
+static void* kValue = static_cast<void*>(new bool{true});
+void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
+
+static void attach(const sp<IBinder>& binder) {
+    binder->attachObject(kId, kValue, nullptr /*cookie*/, clean);
+}
+static bool has(const sp<IBinder>& binder) {
+    return binder != nullptr && binder->findObject(kId) == kValue;
+}
+
+}  // namespace ABBinderTag
+
+namespace ABpBinderTag {
+
+static std::mutex gLock;
+static const void* kId = "ABpBinder";
+struct Value {
+    wp<ABpBinder> binder;
+};
+void clean(const void* id, void* obj, void* cookie) {
+    CHECK(id == kId) << id << " " << obj << " " << cookie;
+
+    delete static_cast<Value*>(obj);
+};
+
+}  // namespace ABpBinderTag
+
+AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
+AIBinder::~AIBinder() {}
+
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
+    if (clazz == nullptr) return false;
+    if (mClazz == clazz) return true;
+
+    String8 newDescriptor(clazz->getInterfaceDescriptor());
+
+    if (mClazz != nullptr) {
+        String8 currentDescriptor(mClazz->getInterfaceDescriptor());
+        if (newDescriptor == currentDescriptor) {
+            LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
+                       << "' match during associateClass, but they are different class objects. "
+                          "Class descriptor collision?";
+        } else {
+            LOG(ERROR) << __func__
+                       << ": Class cannot be associated on object which already has a class. "
+                          "Trying to associate to '"
+                       << newDescriptor.c_str() << "' but already set to '"
+                       << currentDescriptor.c_str() << "'.";
+        }
+
+        // always a failure because we know mClazz != clazz
+        return false;
+    }
+
+    CHECK(asABpBinder() != nullptr);  // ABBinder always has a descriptor
+
+    String8 descriptor(getBinder()->getInterfaceDescriptor());
+    if (descriptor != newDescriptor) {
+        LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str()
+                   << "' but descriptor is actually '" << descriptor.c_str() << "'.";
+        return false;
+    }
+
+    // if this is a local object, it's not one known to libbinder_ndk
+    mClazz = clazz;
+
+    return true;
+}
+
+ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
+    : AIBinder(clazz), BBinder(), mUserData(userData) {
+    CHECK(clazz != nullptr);
+}
+ABBinder::~ABBinder() {
+    getClass()->onDestroy(mUserData);
+}
+
+const String16& ABBinder::getInterfaceDescriptor() const {
+    return getClass()->getInterfaceDescriptor();
+}
+
+status_t ABBinder::dump(int fd, const ::android::Vector<String16>& args) {
+    AIBinder_onDump onDump = getClass()->onDump;
+
+    if (onDump == nullptr) {
+        return STATUS_OK;
+    }
+
+    // technically UINT32_MAX would be okay here, but INT32_MAX is expected since this may be
+    // null in Java
+    if (args.size() > INT32_MAX) {
+        LOG(ERROR) << "ABBinder::dump received too many arguments: " << args.size();
+        return STATUS_BAD_VALUE;
+    }
+
+    std::vector<String8> utf8Args;  // owns memory of utf8s
+    utf8Args.reserve(args.size());
+    std::vector<const char*> utf8Pointers;  // what can be passed over NDK API
+    utf8Pointers.reserve(args.size());
+
+    for (size_t i = 0; i < args.size(); i++) {
+        utf8Args.push_back(String8(args[i]));
+        utf8Pointers.push_back(utf8Args[i].c_str());
+    }
+
+    return onDump(this, fd, utf8Pointers.data(), utf8Pointers.size());
+}
+
+status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
+                              binder_flags_t flags) {
+    if (isUserCommand(code)) {
+        if (!data.checkInterface(this)) {
+            return STATUS_BAD_TYPE;
+        }
+
+        const AParcel in = AParcel::readOnly(this, &data);
+        AParcel out = AParcel(this, reply, false /*owns*/);
+
+        binder_status_t status = getClass()->onTransact(this, code, &in, &out);
+        return PruneStatusT(status);
+    } else {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
+    : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+    CHECK(binder != nullptr);
+}
+ABpBinder::~ABpBinder() {}
+
+void ABpBinder::onLastStrongRef(const void* id) {
+    {
+        std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
+        // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
+        // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no
+        // longer be able to exist at the time of this method call, there is no longer a need to
+        // recover it.
+
+        ABpBinderTag::Value* value =
+                static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
+        if (value != nullptr) {
+            value->binder = nullptr;
+        }
+    }
+
+    BpRefBase::onLastStrongRef(id);
+}
+
+sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+    if (ABBinderTag::has(binder)) {
+        return static_cast<ABBinder*>(binder.get());
+    }
+
+    // The following code ensures that for a given binder object (remote or local), if it is not an
+    // ABBinder then at most one ABpBinder object exists in a given process representing it.
+    std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
+
+    ABpBinderTag::Value* value =
+            static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
+    if (value == nullptr) {
+        value = new ABpBinderTag::Value;
+        binder->attachObject(ABpBinderTag::kId, static_cast<void*>(value), nullptr /*cookie*/,
+                             ABpBinderTag::clean);
+    }
+
+    sp<ABpBinder> ret = value->binder.promote();
+    if (ret == nullptr) {
+        ret = new ABpBinder(binder);
+        value->binder = ret;
+    }
+
+    return ret;
+}
+
+struct AIBinder_Weak {
+    wp<AIBinder> binder;
+};
+AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    return new AIBinder_Weak{wp<AIBinder>(binder)};
+}
+void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) {
+    delete weakBinder;
+}
+AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) {
+    if (weakBinder == nullptr) {
+        return nullptr;
+    }
+
+    sp<AIBinder> binder = weakBinder->binder.promote();
+    AIBinder_incStrong(binder.get());
+    return binder.get();
+}
+
+AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
+                               AIBinder_Class_onDestroy onDestroy,
+                               AIBinder_Class_onTransact onTransact)
+    : onCreate(onCreate),
+      onDestroy(onDestroy),
+      onTransact(onTransact),
+      mInterfaceDescriptor(interfaceDescriptor) {}
+
+AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
+                                      AIBinder_Class_onCreate onCreate,
+                                      AIBinder_Class_onDestroy onDestroy,
+                                      AIBinder_Class_onTransact onTransact) {
+    if (interfaceDescriptor == nullptr || onCreate == nullptr || onDestroy == nullptr ||
+        onTransact == nullptr) {
+        return nullptr;
+    }
+
+    return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
+}
+
+void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) {
+    CHECK(clazz != nullptr) << "setOnDump requires non-null clazz";
+
+    // this is required to be called before instances are instantiated
+    clazz->onDump = onDump;
+}
+
+void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
+    CHECK(who == mWho);
+
+    mOnDied(mCookie);
+
+    sp<AIBinder_DeathRecipient> recipient = mParentRecipient.promote();
+    sp<IBinder> strongWho = who.promote();
+
+    // otherwise this will be cleaned up later with pruneDeadTransferEntriesLocked
+    if (recipient != nullptr && strongWho != nullptr) {
+        status_t result = recipient->unlinkToDeath(strongWho, mCookie);
+        if (result != ::android::DEAD_OBJECT) {
+            LOG(WARNING) << "Unlinking to dead binder resulted in: " << result;
+        }
+    }
+
+    mWho = nullptr;
+}
+
+AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
+    : mOnDied(onDied) {
+    CHECK(onDied != nullptr);
+}
+
+void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() {
+    mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
+                                          [](const sp<TransferDeathRecipient>& tdr) {
+                                              return tdr->getWho() == nullptr;
+                                          }),
+                           mDeathRecipients.end());
+}
+
+binder_status_t AIBinder_DeathRecipient::linkToDeath(sp<IBinder> binder, void* cookie) {
+    CHECK(binder != nullptr);
+
+    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+
+    sp<TransferDeathRecipient> recipient =
+            new TransferDeathRecipient(binder, cookie, this, mOnDied);
+
+    status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/);
+    if (status != STATUS_OK) {
+        return PruneStatusT(status);
+    }
+
+    mDeathRecipients.push_back(recipient);
+
+    pruneDeadTransferEntriesLocked();
+    return STATUS_OK;
+}
+
+binder_status_t AIBinder_DeathRecipient::unlinkToDeath(sp<IBinder> binder, void* cookie) {
+    CHECK(binder != nullptr);
+
+    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+
+    for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
+        sp<TransferDeathRecipient> recipient = *it;
+
+        if (recipient->getCookie() == cookie && recipient->getWho() == binder) {
+            mDeathRecipients.erase(it.base() - 1);
+
+            status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/);
+            if (status != ::android::OK) {
+                LOG(ERROR) << __func__
+                           << ": removed reference to death recipient but unlink failed.";
+            }
+            return PruneStatusT(status);
+        }
+    }
+
+    return STATUS_NAME_NOT_FOUND;
+}
+
+// start of C-API methods
+
+AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
+    if (clazz == nullptr) {
+        LOG(ERROR) << __func__ << ": Must provide class to construct local binder.";
+        return nullptr;
+    }
+
+    void* userData = clazz->onCreate(args);
+
+    sp<AIBinder> ret = new ABBinder(clazz, userData);
+    ABBinderTag::attach(ret->getBinder());
+
+    AIBinder_incStrong(ret.get());
+    return ret.get();
+}
+
+bool AIBinder_isRemote(const AIBinder* binder) {
+    if (binder == nullptr) {
+        return false;
+    }
+
+    return binder->isRemote();
+}
+
+bool AIBinder_isAlive(const AIBinder* binder) {
+    if (binder == nullptr) {
+        return false;
+    }
+
+    return const_cast<AIBinder*>(binder)->getBinder()->isBinderAlive();
+}
+
+binder_status_t AIBinder_ping(AIBinder* binder) {
+    if (binder == nullptr) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    return PruneStatusT(binder->getBinder()->pingBinder());
+}
+
+binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs) {
+    if (binder == nullptr) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    ABBinder* bBinder = binder->asABBinder();
+    if (bBinder != nullptr) {
+        AIBinder_onDump onDump = binder->getClass()->onDump;
+        if (onDump == nullptr) {
+            return STATUS_OK;
+        }
+        return PruneStatusT(onDump(bBinder, fd, args, numArgs));
+    }
+
+    ::android::Vector<String16> utf16Args;
+    utf16Args.setCapacity(numArgs);
+    for (uint32_t i = 0; i < numArgs; i++) {
+        utf16Args.push(String16(String8(args[i])));
+    }
+
+    status_t status = binder->getBinder()->dump(fd, utf16Args);
+    return PruneStatusT(status);
+}
+
+binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                     void* cookie) {
+    if (binder == nullptr || recipient == nullptr) {
+        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    // returns binder_status_t
+    return recipient->linkToDeath(binder->getBinder(), cookie);
+}
+
+binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                       void* cookie) {
+    if (binder == nullptr || recipient == nullptr) {
+        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    // returns binder_status_t
+    return recipient->unlinkToDeath(binder->getBinder(), cookie);
+}
+
+uid_t AIBinder_getCallingUid() {
+    return ::android::IPCThreadState::self()->getCallingUid();
+}
+
+pid_t AIBinder_getCallingPid() {
+    return ::android::IPCThreadState::self()->getCallingPid();
+}
+
+void AIBinder_incStrong(AIBinder* binder) {
+    if (binder == nullptr) {
+        LOG(ERROR) << __func__ << ": on null binder";
+        return;
+    }
+
+    binder->incStrong(nullptr);
+}
+void AIBinder_decStrong(AIBinder* binder) {
+    if (binder == nullptr) {
+        LOG(ERROR) << __func__ << ": on null binder";
+        return;
+    }
+
+    binder->decStrong(nullptr);
+}
+int32_t AIBinder_debugGetRefCount(AIBinder* binder) {
+    if (binder == nullptr) {
+        LOG(ERROR) << __func__ << ": on null binder";
+        return -1;
+    }
+
+    return binder->getStrongCount();
+}
+
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) {
+    if (binder == nullptr) {
+        return false;
+    }
+
+    return binder->associateClass(clazz);
+}
+
+const AIBinder_Class* AIBinder_getClass(AIBinder* binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    return binder->getClass();
+}
+
+void* AIBinder_getUserData(AIBinder* binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    ABBinder* bBinder = binder->asABBinder();
+    if (bBinder == nullptr) {
+        return nullptr;
+    }
+
+    return bBinder->getUserData();
+}
+
+binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
+    if (binder == nullptr || in == nullptr) {
+        LOG(ERROR) << __func__ << ": requires non-null parameters.";
+        return STATUS_UNEXPECTED_NULL;
+    }
+    const AIBinder_Class* clazz = binder->getClass();
+    if (clazz == nullptr) {
+        LOG(ERROR) << __func__
+                   << ": Class must be defined for a remote binder transaction. See "
+                      "AIBinder_associateClass.";
+        return STATUS_INVALID_OPERATION;
+    }
+
+    if (!binder->isRemote()) {
+        LOG(WARNING) << "A binder object at " << binder
+                     << " is being transacted on, however, this object is in the same process as "
+                        "its proxy. Transacting with this binder is expensive compared to just "
+                        "calling the corresponding functionality in the same process.";
+    }
+
+    *in = new AParcel(binder);
+    status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+    binder_status_t ret = PruneStatusT(status);
+
+    if (ret != STATUS_OK) {
+        delete *in;
+        *in = nullptr;
+    }
+
+    return ret;
+}
+
+static void DestroyParcel(AParcel** parcel) {
+    delete *parcel;
+    *parcel = nullptr;
+}
+
+binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
+                                  AParcel** out, binder_flags_t flags) {
+    if (in == nullptr) {
+        LOG(ERROR) << __func__ << ": requires non-null in parameter";
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>;
+    // This object is the input to the transaction. This function takes ownership of it and deletes
+    // it.
+    AutoParcelDestroyer forIn(in, DestroyParcel);
+
+    if (!isUserCommand(code)) {
+        LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
+        return STATUS_UNKNOWN_TRANSACTION;
+    }
+
+    if ((flags & ~FLAG_ONEWAY) != 0) {
+        LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags;
+        return STATUS_BAD_VALUE;
+    }
+
+    if (binder == nullptr || *in == nullptr || out == nullptr) {
+        LOG(ERROR) << __func__ << ": requires non-null parameters.";
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    if ((*in)->getBinder() != binder) {
+        LOG(ERROR) << __func__ << ": parcel is associated with binder object " << binder
+                   << " but called with " << (*in)->getBinder();
+        return STATUS_BAD_VALUE;
+    }
+
+    *out = new AParcel(binder);
+
+    status_t status = binder->getBinder()->transact(code, *(*in)->get(), (*out)->get(), flags);
+    binder_status_t ret = PruneStatusT(status);
+
+    if (ret != STATUS_OK) {
+        delete *out;
+        *out = nullptr;
+    }
+
+    return ret;
+}
+
+AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
+        AIBinder_DeathRecipient_onBinderDied onBinderDied) {
+    if (onBinderDied == nullptr) {
+        LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter.";
+        return nullptr;
+    }
+    auto ret = new AIBinder_DeathRecipient(onBinderDied);
+    ret->incStrong(nullptr);
+    return ret;
+}
+
+void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) {
+    if (recipient == nullptr) {
+        return;
+    }
+
+    recipient->decStrong(nullptr);
+}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
new file mode 100644
index 0000000..5cb68c2
--- /dev/null
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include "ibinder_internal.h"
+
+#include <atomic>
+#include <mutex>
+#include <vector>
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <utils/Vector.h>
+
+inline bool isUserCommand(transaction_code_t code) {
+    return code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION;
+}
+
+struct ABBinder;
+struct ABpBinder;
+
+struct AIBinder : public virtual ::android::RefBase {
+    explicit AIBinder(const AIBinder_Class* clazz);
+    virtual ~AIBinder();
+
+    bool associateClass(const AIBinder_Class* clazz);
+    const AIBinder_Class* getClass() const { return mClazz; }
+
+    virtual ::android::sp<::android::IBinder> getBinder() = 0;
+    virtual ABBinder* asABBinder() { return nullptr; }
+    virtual ABpBinder* asABpBinder() { return nullptr; }
+
+    bool isRemote() const {
+        ::android::sp<::android::IBinder> binder = const_cast<AIBinder*>(this)->getBinder();
+        return binder->remoteBinder() != nullptr;
+    }
+
+   private:
+    // AIBinder instance is instance of this class for a local object. In order to transact on a
+    // remote object, this also must be set for simplicity (although right now, only the
+    // interfaceDescriptor from it is used).
+    const AIBinder_Class* mClazz;
+};
+
+// This is a local AIBinder object with a known class.
+struct ABBinder : public AIBinder, public ::android::BBinder {
+    virtual ~ABBinder();
+
+    void* getUserData() { return mUserData; }
+
+    ::android::sp<::android::IBinder> getBinder() override { return this; }
+    ABBinder* asABBinder() override { return this; }
+
+    const ::android::String16& getInterfaceDescriptor() const override;
+    ::android::status_t dump(int fd, const ::android::Vector<::android::String16>& args) override;
+    ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
+                                   ::android::Parcel* reply, binder_flags_t flags) override;
+
+   private:
+    ABBinder(const AIBinder_Class* clazz, void* userData);
+
+    // only thing that should create an ABBinder
+    friend AIBinder* AIBinder_new(const AIBinder_Class*, void*);
+
+    // Can contain implementation if this is a local binder. This can still be nullptr for a local
+    // binder. If it is nullptr, the implication is the implementation state is entirely external to
+    // this object and the functionality provided in the AIBinder_Class is sufficient.
+    void* mUserData;
+};
+
+// This binder object may be remote or local (even though it is 'Bp'). The implication if it is
+// local is that it is an IBinder object created outside of the domain of libbinder_ndk.
+struct ABpBinder : public AIBinder, public ::android::BpRefBase {
+    // Looks up to see if this object has or is an existing ABBinder or ABpBinder object, otherwise
+    // it creates an ABpBinder object.
+    static ::android::sp<AIBinder> lookupOrCreateFromBinder(
+            const ::android::sp<::android::IBinder>& binder);
+
+    virtual ~ABpBinder();
+
+    void onLastStrongRef(const void* id) override;
+
+    ::android::sp<::android::IBinder> getBinder() override { return remote(); }
+    ABpBinder* asABpBinder() override { return this; }
+
+   private:
+    explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
+};
+
+struct AIBinder_Class {
+    AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
+                   AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);
+
+    const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
+
+    // required to be non-null, implemented for every class
+    const AIBinder_Class_onCreate onCreate;
+    const AIBinder_Class_onDestroy onDestroy;
+    const AIBinder_Class_onTransact onTransact;
+
+    // optional methods for a class
+    AIBinder_onDump onDump;
+
+   private:
+    // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
+    // one.
+    const ::android::String16 mInterfaceDescriptor;
+};
+
+// Ownership is like this (when linked to death):
+//
+//   AIBinder_DeathRecipient -sp-> TransferDeathRecipient <-wp-> IBinder
+//
+// When the AIBinder_DeathRecipient is dropped, so are the actual underlying death recipients. When
+// the IBinder dies, only a wp to it is kept.
+struct AIBinder_DeathRecipient : ::android::RefBase {
+    // One of these is created for every linkToDeath. This is to be able to recover data when a
+    // binderDied receipt only gives us information about the IBinder.
+    struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
+        TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
+                               const ::android::wp<AIBinder_DeathRecipient>& parentRecipient,
+                               const AIBinder_DeathRecipient_onBinderDied onDied)
+            : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {}
+
+        void binderDied(const ::android::wp<::android::IBinder>& who) override;
+
+        const ::android::wp<::android::IBinder>& getWho() { return mWho; }
+        void* getCookie() { return mCookie; }
+
+       private:
+        ::android::wp<::android::IBinder> mWho;
+        void* mCookie;
+
+        ::android::wp<AIBinder_DeathRecipient> mParentRecipient;
+
+        // This is kept separately from AIBinder_DeathRecipient in case the death recipient is
+        // deleted while the death notification is fired
+        const AIBinder_DeathRecipient_onBinderDied mOnDied;
+    };
+
+    explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
+    binder_status_t linkToDeath(::android::sp<::android::IBinder>, void* cookie);
+    binder_status_t unlinkToDeath(::android::sp<::android::IBinder> binder, void* cookie);
+
+   private:
+    // When the user of this API deletes a Bp object but not the death recipient, the
+    // TransferDeathRecipient object can't be cleaned up. This is called whenever a new
+    // TransferDeathRecipient is linked, and it ensures that mDeathRecipients can't grow unbounded.
+    void pruneDeadTransferEntriesLocked();
+
+    std::mutex mDeathRecipientsMutex;
+    std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
+    AIBinder_DeathRecipient_onBinderDied mOnDied;
+};
diff --git a/libs/binder/ndk/ibinder_jni.cpp b/libs/binder/ndk/ibinder_jni.cpp
new file mode 100644
index 0000000..d931785
--- /dev/null
+++ b/libs/binder/ndk/ibinder_jni.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_ibinder_jni.h>
+#include "ibinder_internal.h"
+
+#include <android_util_Binder.h>
+
+using ::android::IBinder;
+using ::android::ibinderForJavaObject;
+using ::android::javaObjectForIBinder;
+using ::android::sp;
+
+AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    sp<IBinder> ibinder = ibinderForJavaObject(env, binder);
+    sp<AIBinder> cbinder = ABpBinder::lookupOrCreateFromBinder(ibinder);
+    AIBinder_incStrong(cbinder.get());
+
+    return cbinder.get();
+}
+
+jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    return javaObjectForIBinder(env, binder->getBinder());
+}
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
new file mode 100644
index 0000000..055c79b
--- /dev/null
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <android/binder_status.h>
+
+__BEGIN_DECLS
+
+/**
+ * This registers the service with the default service manager under this instance name. This does
+ * not take ownership of binder.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
+
+/**
+ * Gets a binder object with this specific instance name. Will return nullptr immediately if the
+ * service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
+ * function is responsible for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+
+/**
+ * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
+ * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
+ * for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_apex/android/binder_process.h
new file mode 100644
index 0000000..69e6387
--- /dev/null
+++ b/libs/binder/ndk/include_apex/android/binder_process.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * This creates a threadpool for incoming binder transactions if it has not already been created.
+ */
+void ABinderProcess_startThreadPool();
+/**
+ * This sets the maximum number of threads that can be started in the threadpool. By default, after
+ * startThreadPool is called, this is one. If it is called additional times, it will only prevent
+ * the kernel from starting new threads and will not delete already existing threads.
+ */
+bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
+/**
+ * This adds the current thread to the threadpool. This may cause the threadpool to exceed the
+ * maximum size.
+ */
+void ABinderProcess_joinThreadPool();
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
new file mode 100644
index 0000000..c6868b0
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_auto_utils.h
+ * @brief These objects provide a more C++-like thin interface to the .
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <android/binder_parcel.h>
+#include <android/binder_status.h>
+
+#include <assert.h>
+
+#include <unistd.h>
+#include <cstddef>
+
+namespace ndk {
+
+/**
+ * Represents one strong pointer to an AIBinder object.
+ */
+class SpAIBinder {
+   public:
+    /**
+     * Takes ownership of one strong refcount of binder.
+     */
+    explicit SpAIBinder(AIBinder* binder = nullptr) : mBinder(binder) {}
+
+    /**
+     * Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not
+     * explicit because it is not taking ownership of anything.
+     */
+    SpAIBinder(std::nullptr_t) : SpAIBinder() {}  // NOLINT(google-explicit-constructor)
+
+    /**
+     * This will delete the underlying object if it exists. See operator=.
+     */
+    SpAIBinder(const SpAIBinder& other) { *this = other; }
+
+    /**
+     * This deletes the underlying object if it exists. See set.
+     */
+    ~SpAIBinder() { set(nullptr); }
+
+    /**
+     * This takes ownership of a binder from another AIBinder object but it does not affect the
+     * ownership of that other object.
+     */
+    SpAIBinder& operator=(const SpAIBinder& other) {
+        AIBinder_incStrong(other.mBinder);
+        set(other.mBinder);
+        return *this;
+    }
+
+    /**
+     * Takes ownership of one strong refcount of binder
+     */
+    void set(AIBinder* binder) {
+        AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder);
+        if (old != nullptr) AIBinder_decStrong(old);
+        if (old != *const_cast<AIBinder* volatile*>(&mBinder)) {
+            __assert(__FILE__, __LINE__, "Race detected.");
+        }
+        mBinder = binder;
+    }
+
+    /**
+     * This returns the underlying binder object for transactions. If it is used to create another
+     * SpAIBinder object, it should first be incremented.
+     */
+    AIBinder* get() const { return mBinder; }
+
+    /**
+     * This allows the value in this class to be set from beneath it. If you call this method and
+     * then change the value of T*, you must take ownership of the value you are replacing and add
+     * ownership to the object that is put in here.
+     *
+     * Recommended use is like this:
+     *   SpAIBinder a;  // will be nullptr
+     *   SomeInitFunction(a.getR());  // value is initialized with refcount
+     *
+     * Other usecases are discouraged.
+     *
+     */
+    AIBinder** getR() { return &mBinder; }
+
+   private:
+    AIBinder* mBinder = nullptr;
+};
+
+namespace impl {
+
+/**
+ * This baseclass owns a single object, used to make various classes RAII.
+ */
+template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
+class ScopedAResource {
+   public:
+    /**
+     * Takes ownership of t.
+     */
+    explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
+
+    /**
+     * This deletes the underlying object if it exists. See set.
+     */
+    ~ScopedAResource() { set(DEFAULT); }
+
+    /**
+     * Takes ownership of t.
+     */
+    void set(T t) {
+        Destroy(mT);
+        mT = t;
+    }
+
+    /**
+     * This returns the underlying object to be modified but does not affect ownership.
+     */
+    T get() { return mT; }
+
+    /**
+     * This returns the const underlying object but does not affect ownership.
+     */
+    const T get() const { return mT; }
+
+    /**
+     * This allows the value in this class to be set from beneath it. If you call this method and
+     * then change the value of T*, you must take ownership of the value you are replacing and add
+     * ownership to the object that is put in here.
+     *
+     * Recommended use is like this:
+     *   ScopedAResource<T> a; // will be nullptr
+     *   SomeInitFunction(a.getR()); // value is initialized with refcount
+     *
+     * Other usecases are discouraged.
+     *
+     */
+    T* getR() { return &mT; }
+
+    // copy-constructing, or move/copy assignment is disallowed
+    ScopedAResource(const ScopedAResource&) = delete;
+    ScopedAResource& operator=(const ScopedAResource&) = delete;
+    ScopedAResource& operator=(ScopedAResource&&) = delete;
+
+    // move-constructing is okay
+    ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; }
+
+   private:
+    T mT;
+};
+
+}  // namespace impl
+
+/**
+ * Convenience wrapper. See AParcel.
+ */
+class ScopedAParcel : public impl::ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
+    ~ScopedAParcel() {}
+    ScopedAParcel(ScopedAParcel&&) = default;
+};
+
+/**
+ * Convenience wrapper. See AStatus.
+ */
+class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
+    ~ScopedAStatus() {}
+    ScopedAStatus(ScopedAStatus&&) = default;
+
+    /**
+     * See AStatus_isOk.
+     */
+    bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+
+    /**
+     * Convenience method for okay status.
+     */
+    static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
+};
+
+/**
+ * Convenience wrapper. See AIBinder_DeathRecipient.
+ */
+class ScopedAIBinder_DeathRecipient
+    : public impl::ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+                                   nullptr> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
+        : ScopedAResource(a) {}
+    ~ScopedAIBinder_DeathRecipient() {}
+    ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
+};
+
+/**
+ * Convenience wrapper. See AIBinder_Weak.
+ */
+class ScopedAIBinder_Weak
+    : public impl::ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
+    ~ScopedAIBinder_Weak() {}
+    ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
+
+    /**
+     * See AIBinder_Weak_promote.
+     */
+    SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
+};
+
+/**
+ * Convenience wrapper for a file descriptor.
+ */
+class ScopedFileDescriptor : public impl::ScopedAResource<int, int, close, -1> {
+   public:
+    /**
+     * Takes ownership of a.
+     */
+    explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+    ~ScopedFileDescriptor() {}
+    ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+};
+
+}  // namespace ndk
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
new file mode 100644
index 0000000..80d1254
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_ibinder.h
+ * @brief Object which can receive transactions and be sent across processes.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <android/binder_parcel.h>
+#include <android/binder_status.h>
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+// Also see TF_* in kernel's binder.h
+typedef uint32_t binder_flags_t;
+enum {
+    /**
+     * The transaction will be dispatched and then returned to the caller. The outgoing process
+     * cannot block a call made by this, and execution of the call will not be waited on. An error
+     * can still be returned if the call is unable to be processed by the binder driver. All oneway
+     * calls are guaranteed to be ordered if they are sent on the same AIBinder object.
+     */
+    FLAG_ONEWAY = 0x01,
+};
+
+// Also see IBinder.h in libbinder
+typedef uint32_t transaction_code_t;
+enum {
+    /**
+     * The first transaction code available for user commands (inclusive).
+     */
+    FIRST_CALL_TRANSACTION = 0x00000001,
+    /**
+     * The last transaction code available for user commands (inclusive).
+     */
+    LAST_CALL_TRANSACTION = 0x00ffffff,
+};
+
+/**
+ * Represents a type of AIBinder object which can be sent out.
+ */
+struct AIBinder_Class;
+typedef struct AIBinder_Class AIBinder_Class;
+
+/**
+ * Represents a local or remote object which can be used for IPC or which can itself be sent.
+ *
+ * This object has a refcount associated with it and will be deleted when its refcount reaches zero.
+ * How methods interactive with this refcount is described below. When using this API, it is
+ * intended for a client of a service to hold a strong reference to that service. This also means
+ * that user data typically should hold a strong reference to a local AIBinder object. A remote
+ * AIBinder object automatically holds a strong reference to the AIBinder object in the server's
+ * process. A typically memory layout looks like this:
+ *
+ * Key:
+ *   --->         Ownership/a strong reference
+ *   ...>         A weak reference
+ *
+ *                         (process boundary)
+ *                                 |
+ * MyInterface ---> AIBinder_Weak  |  ProxyForMyInterface
+ *      ^                .         |          |
+ *      |                .         |          |
+ *      |                v         |          v
+ *   UserData  <---   AIBinder   <-|-      AIBinder
+ *                                 |
+ *
+ * In this way, you'll notice that a proxy for the interface holds a strong reference to the
+ * implementation and that in the server process, the AIBinder object which was sent can be resent
+ * so that the same AIBinder object always represents the same object. This allows, for instance, an
+ * implementation (usually a callback) to transfer all ownership to a remote process and
+ * automatically be deleted when the remote process is done with it or dies. Other memory models are
+ * possible, but this is the standard one.
+ *
+ * If the process containing an AIBinder dies, it is possible to be holding a strong reference to
+ * an object which does not exist. In this case, transactions to this binder will return
+ * STATUS_DEAD_OBJECT. See also AIBinder_linkToDeath, AIBinder_unlinkToDeath, and AIBinder_isAlive.
+ *
+ * Once an AIBinder is created, anywhere it is passed (remotely or locally), there is a 1-1
+ * correspondence between the address of an AIBinder and the object it represents. This means that
+ * when two AIBinder pointers point to the same address, they represent the same object (whether
+ * that object is local or remote). This correspondance can be broken accidentally if AIBinder_new
+ * is erronesouly called to create the same object multiple times.
+ */
+struct AIBinder;
+typedef struct AIBinder AIBinder;
+
+/**
+ * The AIBinder object associated with this can be retrieved if it is still alive so that it can be
+ * re-used. The intention of this is to enable the same AIBinder object to always represent the same
+ * object.
+ */
+struct AIBinder_Weak;
+typedef struct AIBinder_Weak AIBinder_Weak;
+
+/**
+ * Represents a handle on a death notification. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ */
+struct AIBinder_DeathRecipient;
+typedef struct AIBinder_DeathRecipient AIBinder_DeathRecipient;
+
+/**
+ * This is called whenever a new AIBinder object is needed of a specific class.
+ *
+ * \param args these can be used to construct a new class. These are passed from AIBinder_new.
+ * \return this is the userdata representing the class. It can be retrieved using
+ * AIBinder_getUserData.
+ */
+typedef void* (*AIBinder_Class_onCreate)(void* args);
+
+/**
+ * This is called whenever an AIBinder object is no longer referenced and needs destroyed.
+ *
+ * Typically, this just deletes whatever the implementation is.
+ *
+ * \param userData this is the same object returned by AIBinder_Class_onCreate
+ */
+typedef void (*AIBinder_Class_onDestroy)(void* userData);
+
+/**
+ * This is called whenever a transaction needs to be processed by a local implementation.
+ *
+ * \param binder the object being transacted on.
+ * \param code implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ *
+ * \return the implementation-specific output code. This may be forwarded from another service, the
+ * result of a parcel read or write, or another error as is applicable to the specific
+ * implementation. Usually, implementation-specific error codes are written to the output parcel,
+ * and the transaction code is reserved for kernel errors or error codes that have been repeated
+ * from subsequent transactions.
+ */
+typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code,
+                                                     const AParcel* in, AParcel* out);
+
+/**
+ * This creates a new instance of a class of binders which can be instantiated. This is called one
+ * time during library initialization and cleaned up when the process exits or execs.
+ *
+ * None of these parameters can be null.
+ *
+ * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
+ * sanity checks on transactions.
+ * \param onCreate see AIBinder_Class_onCreate.
+ * \param onDestroy see AIBinder_Class_onDestroy.
+ * \param onTransact see AIBinder_Class_onTransact.
+ *
+ * \return the class object representing these parameters or null on error.
+ */
+__attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
+        const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
+        AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact)
+        __INTRODUCED_IN(29);
+
+/**
+ * Dump information about an AIBinder (usually for debugging).
+ *
+ * When no arguments are provided, a brief overview of the interview should be given.
+ *
+ * \param binder interface being dumped
+ * \param fd file descriptor to be dumped to, should be flushed, ownership is not passed.
+ * \param args array of null-terminated strings for dump (may be null if numArgs is 0)
+ * \param numArgs number of args to be sent
+ *
+ * \return binder_status_t result of transaction (if remote, for instance)
+ */
+typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char** args,
+                                           uint32_t numArgs);
+
+/**
+ * This sets the implementation of the dump method for a class.
+ *
+ * If this isn't set, nothing will be dumped when dump is called (for instance with
+ * android.os.Binder#dump). Must be called before any instance of the class is created.
+ *
+ * \param dump function to call when an instance of this binder class is being dumped.
+ */
+void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
+
+/**
+ * Creates a new binder object of the appropriate class.
+ *
+ * Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
+ * and AIBinder_decStrong. When the reference count reaches zero, onDestroy is called.
+ *
+ * When this is called, the refcount is implicitly 1. So, calling decStrong exactly one time is
+ * required to delete this object.
+ *
+ * Once an AIBinder object is created using this API, re-creating that AIBinder for the same
+ * instance of the same class will break pointer equality for that specific AIBinder object. For
+ * instance, if someone erroneously created two AIBinder instances representing the same callback
+ * object and passed one to a hypothetical addCallback function and then later another one to a
+ * hypothetical removeCallback function, the remote process would have no way to determine that
+ * these two objects are actually equal using the AIBinder pointer alone (which they should be able
+ * to do). Also see the suggested memory ownership model suggested above.
+ *
+ * \param clazz the type of the object to be created.
+ * \param args the args to pass to AIBinder_onCreate for that class.
+ *
+ * \return a binder object representing the newly instantiated object.
+ */
+__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args)
+        __INTRODUCED_IN(29);
+
+/**
+ * If this is hosted in a process other than the current one.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the AIBinder represents an object in another process.
+ */
+bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * If this binder is known to be alive. This will not send a transaction to a remote process and
+ * returns a result based on the last known information. That is, whenever a transaction is made,
+ * this is automatically updated to reflect the current alive status of this binder. This will be
+ * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
+ * based on the results of bookkeeping or other transactions made internally.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the binder is alive.
+ */
+bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * Built-in transaction for all binder objects. This sends a transaction that will immediately
+ * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
+ * sanity check.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return STATUS_OK if the ping succeeds.
+ */
+binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * Built-in transaction for all binder objects. This dumps information about a given binder.
+ *
+ * See also AIBinder_Class_setOnDump, AIBinder_onDump
+ *
+ * \param binder the binder to dump information about
+ * \param fd where information should be dumped to
+ * \param args null-terminated arguments to pass (may be null if numArgs is 0)
+ * \param numArgs number of args to send
+ *
+ * \return STATUS_OK if dump succeeds (or if there is nothing to dump)
+ */
+binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint32_t numArgs)
+        __INTRODUCED_IN(29);
+
+/**
+ * Registers for notifications that the associated binder is dead. The same death recipient may be
+ * associated with multiple different binders. If the binder is local, then no death recipient will
+ * be given (since if the local process dies, then no recipient will exist to recieve a
+ * transaction). The cookie is passed to recipient in the case that this binder dies and can be
+ * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
+ * This function may return a binder transaction failure. The cookie can be used both for
+ * identification and holding user data.
+ *
+ * If binder is local, this will return STATUS_INVALID_OPERATION.
+ *
+ * \param binder the binder object you want to receive death notifications from.
+ * \param recipient the callback that will receive notifications when/if the binder dies.
+ * \param cookie the value that will be passed to the death recipient on death.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                     void* cookie) __INTRODUCED_IN(29);
+
+/**
+ * Stops registration for the associated binder dying. Does not delete the recipient. This function
+ * may return a binder transaction failure and in case the death recipient cannot be found, it
+ * returns STATUS_NAME_NOT_FOUND.
+ *
+ * This only ever needs to be called when the AIBinder_DeathRecipient remains for use with other
+ * AIBinder objects. If the death recipient is deleted, all binders will automatically be unlinked.
+ * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
+ * automatically unlinked.
+ *
+ * \param binder the binder object to remove a previously linked death recipient from.
+ * \param recipient the callback to remove.
+ * \param cookie the cookie used to link to death.
+ *
+ * \return STATUS_OK on success. STATUS_NAME_NOT_FOUND if the binder cannot be found to be unlinked.
+ */
+binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                       void* cookie) __INTRODUCED_IN(29);
+
+/**
+ * This returns the calling UID assuming that this thread is called from a thread that is processing
+ * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact).
+ *
+ * This can be used with higher-level system services to determine the caller's identity and check
+ * permissions.
+ *
+ * \return calling uid or the current process's UID if this thread isn't processing a transaction.
+ */
+uid_t AIBinder_getCallingUid();
+
+/**
+ * This returns the calling PID assuming that this thread is called from a thread that is processing
+ * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact).
+ *
+ * This can be used with higher-level system services to determine the caller's identity and check
+ * permissions. However, when doing this, one should be aware of possible TOCTOU problems when the
+ * calling process dies and is replaced with another process with elevated permissions and the same
+ * PID.
+ *
+ * \return calling pid or the current process's PID if this thread isn't processing a transaction.
+ * If the transaction being processed is a oneway transaction, then this method will return 0.
+ */
+pid_t AIBinder_getCallingPid();
+
+/**
+ * This can only be called if a strong reference to this object already exists in process.
+ *
+ * \param binder the binder object to add a refcount to.
+ */
+void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * This will delete the object and call onDestroy once the refcount reaches zero.
+ *
+ * \param binder the binder object to remove a refcount from.
+ */
+void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * For debugging only!
+ *
+ * \param binder the binder object to retrieve the refcount of.
+ *
+ * \return the number of strong-refs on this binder in this process. If binder is null, this will be
+ * -1.
+ */
+int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * This sets the class of an AIBinder object. This checks to make sure the remote object is of
+ * the expected class. A class must be set in order to use transactions on an AIBinder object.
+ * However, if an object is just intended to be passed through to another process or used as a
+ * handle this need not be called.
+ *
+ * This returns true if the class association succeeds. If it fails, no change is made to the
+ * binder object.
+ *
+ * \param binder the object to attach the class to.
+ * \param clazz the clazz to attach to binder.
+ *
+ * \return true if the binder has the class clazz and if the association was successful.
+ */
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29);
+
+/**
+ * Returns the class that this binder was constructed with or associated with.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the class that this binder is associated with. If this binder wasn't created with
+ * AIBinder_new, and AIBinder_associateClass hasn't been called, then this will return null.
+ */
+const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
+ * null), this also returns null. For a remote binder, this will always return null.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
+ * null for stateless objects. For remote objects, this is always null.
+ */
+void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * A transaction is a series of calls to these functions which looks this
+ * - call AIBinder_prepareTransaction
+ * - fill out the in parcel with parameters (lifetime of the 'in' variable)
+ * - call AIBinder_transact
+ * - read results from the out parcel (lifetime of the 'out' variable)
+ */
+
+/**
+ * Creates a parcel to start filling out for a transaction. This may add data to the parcel for
+ * security, debugging, or other purposes. This parcel is to be sent via AIBinder_transact and it
+ * represents the input data to the transaction. It is recommended to check if the object is local
+ * and call directly into its user data before calling this as the parceling and unparceling cost
+ * can be avoided. This AIBinder must be either built with a class or associated with a class before
+ * using this API.
+ *
+ * This does not affect the ownership of binder. When this function succeeds, the in parcel's
+ * ownership is passed to the caller. At this point, the parcel can be filled out and passed to
+ * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
+ * deleted with AParcel_delete.
+ *
+ * \param binder the binder object to start a transaction on.
+ * \param in out parameter for input data to the transaction.
+ *
+ * \return STATUS_OK on success. This will return STATUS_INVALID_OPERATION if the binder has not yet
+ * been associated with a class (see AIBinder_new and AIBinder_associateClass).
+ */
+binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29);
+
+/**
+ * Transact using a parcel created from AIBinder_prepareTransaction. This actually communicates with
+ * the object representing this binder object. This also passes out a parcel to be used for the
+ * return transaction. This takes ownership of the in parcel and automatically deletes it after it
+ * is sent to the remote process. The output parcel is the result of the transaction. If the
+ * transaction has FLAG_ONEWAY, the out parcel will be empty. Otherwise, this will block until the
+ * remote process has processed the transaction, and the out parcel will contain the output data
+ * from transaction.
+ *
+ * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
+ * and must be released with AParcel_delete when finished reading.
+ *
+ * \param binder the binder object to transact on.
+ * \param code the implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ * \param flags possible flags to alter the way in which the transaction is conducted or 0.
+ *
+ * \return the result from the kernel or from the remote process. Usually, implementation-specific
+ * error codes are written to the output parcel, and the transaction code is reserved for kernel
+ * errors or error codes that have been repeated from subsequent transactions.
+ */
+binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
+                                  AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29);
+
+/**
+ * This does not take any ownership of the input binder, but it can be used to retrieve it if
+ * something else in some process still holds a reference to it.
+ *
+ * \param binder object to create a weak pointer to.
+ *
+ * \return object representing a weak pointer to binder (or null if binder is null).
+ */
+__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder)
+        __INTRODUCED_IN(29);
+
+/**
+ * Deletes the weak reference. This will have no impact on the lifetime of the binder.
+ *
+ * \param weakBinder object created with AIBinder_Weak_new.
+ */
+void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
+
+/**
+ * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
+ * null.
+ *
+ * \param weakBinder weak pointer to attempt retrieving the original object from.
+ *
+ * \return an AIBinder object with one refcount given to the caller or null.
+ */
+__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder)
+        __INTRODUCED_IN(29);
+
+/**
+ * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
+ */
+typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
+
+/**
+ * Creates a new binder death recipient. This can be attached to multiple different binder objects.
+ *
+ * \param onBinderDied the callback to call when this death recipient is invoked.
+ *
+ * \return the newly constructed object (or null if onBinderDied is null).
+ */
+__attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
+        AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
+
+/**
+ * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
+ * calling this as these will all be automatically unlinked.
+ *
+ * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
+ */
+void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
+
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
new file mode 100644
index 0000000..124f36c
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_ibinder_jni.h
+ * @brief Conversions between AIBinder and android.os.IBinder
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+/**
+ * Converts an android.os.IBinder object into an AIBinder* object.
+ *
+ * If either env or the binder is null, null is returned. If this binder object was originally an
+ * AIBinder object, the original object is returned. The returned object has one refcount
+ * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
+ *
+ * \param env Java environment.
+ * \param binder android.os.IBinder java object.
+ *
+ * \return an AIBinder object representing the Java binder object. If either parameter is null, or
+ * the Java object is of the wrong type, this will return null.
+ */
+__attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder)
+        __INTRODUCED_IN(29);
+
+/**
+ * Converts an AIBinder* object into an android.os.IBinder object.
+ *
+ * If either env or the binder is null, null is returned. If this binder object was originally an
+ * IBinder object, the original java object will be returned.
+ *
+ * \param env Java environment.
+ * \param binder the object to convert.
+ *
+ * \return an android.os.IBinder object or null if the parameters were null.
+ */
+__attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
+        __INTRODUCED_IN(29);
+
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
new file mode 100644
index 0000000..83a1048
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_interface_utils.h
+ * @brief This provides common C++ classes for common operations and as base classes for C++
+ * interfaces.
+ */
+
+#pragma once
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+
+#include <assert.h>
+
+#include <memory>
+#include <mutex>
+
+namespace ndk {
+
+/**
+ * analog using std::shared_ptr for internally held refcount
+ *
+ * ref must be called at least one time during the lifetime of this object. The recommended way to
+ * construct this object is with SharedRefBase::make.
+ */
+class SharedRefBase {
+   public:
+    SharedRefBase() {}
+    virtual ~SharedRefBase() {
+        std::call_once(mFlagThis, [&]() {
+            __assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
+        });
+    }
+
+    /**
+     * A shared_ptr must be held to this object when this is called. This must be called once during
+     * the lifetime of this object.
+     */
+    std::shared_ptr<SharedRefBase> ref() {
+        std::shared_ptr<SharedRefBase> thiz = mThis.lock();
+
+        std::call_once(mFlagThis, [&]() { mThis = thiz = std::shared_ptr<SharedRefBase>(this); });
+
+        return thiz;
+    }
+
+    /**
+     * Convenience method for a ref (see above) which automatically casts to the desired child type.
+     */
+    template <typename CHILD>
+    std::shared_ptr<CHILD> ref() {
+        return std::static_pointer_cast<CHILD>(ref());
+    }
+
+    /**
+     * Convenience method for making an object directly with a reference.
+     */
+    template <class T, class... Args>
+    static std::shared_ptr<T> make(Args&&... args) {
+        T* t = new T(std::forward<Args>(args)...);
+        return t->template ref<T>();
+    }
+
+   private:
+    std::once_flag mFlagThis;
+    std::weak_ptr<SharedRefBase> mThis;
+};
+
+/**
+ * wrapper analog to IInterface
+ */
+class ICInterface : public SharedRefBase {
+   public:
+    ICInterface() {}
+    virtual ~ICInterface() {}
+
+    /**
+     * This either returns the single existing implementation or creates a new implementation.
+     */
+    virtual SpAIBinder asBinder() = 0;
+
+    /**
+     * Returns whether this interface is in a remote process. If it cannot be determined locally,
+     * this will be checked using AIBinder_isRemote.
+     */
+    virtual bool isRemote() = 0;
+
+    /**
+     * Dumps information about the interface. By default, dumps nothing.
+     */
+    virtual inline binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+
+    /**
+     * Interprets this binder as this underlying interface if this has stored an ICInterface in the
+     * binder's user data.
+     *
+     * This does not do type checking and should only be used when the binder is known to originate
+     * from ICInterface. Most likely, you want to use I*::fromBinder.
+     */
+    static inline std::shared_ptr<ICInterface> asInterface(AIBinder* binder);
+
+    /**
+     * Helper method to create a class
+     */
+    static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
+                                              AIBinder_Class_onTransact onTransact);
+
+   private:
+    class ICInterfaceData {
+       public:
+        std::shared_ptr<ICInterface> interface;
+
+        static inline std::shared_ptr<ICInterface> getInterface(AIBinder* binder);
+
+        static inline void* onCreate(void* args);
+        static inline void onDestroy(void* userData);
+        static inline binder_status_t onDump(AIBinder* binder, int fd, const char** args,
+                                             uint32_t numArgs);
+    };
+};
+
+/**
+ * implementation of IInterface for server (n = native)
+ */
+template <typename INTERFACE>
+class BnCInterface : public INTERFACE {
+   public:
+    BnCInterface() {}
+    virtual ~BnCInterface() {}
+
+    SpAIBinder asBinder() override;
+
+    bool isRemote() override { return false; }
+
+   protected:
+    /**
+     * This function should only be called by asBinder. Otherwise, there is a possibility of
+     * multiple AIBinder* objects being created for the same instance of an object.
+     */
+    virtual SpAIBinder createBinder() = 0;
+
+   private:
+    std::mutex mMutex;  // for asBinder
+    ScopedAIBinder_Weak mWeakBinder;
+};
+
+/**
+ * implementation of IInterface for client (p = proxy)
+ */
+template <typename INTERFACE>
+class BpCInterface : public INTERFACE {
+   public:
+    explicit BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
+    virtual ~BpCInterface() {}
+
+    SpAIBinder asBinder() override;
+
+    bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
+        return AIBinder_dump(asBinder().get(), fd, args, numArgs);
+    }
+
+   private:
+    SpAIBinder mBinder;
+};
+
+// END OF CLASS DECLARATIONS
+
+binder_status_t ICInterface::dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/) {
+    return STATUS_OK;
+}
+
+std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) {
+    return ICInterfaceData::getInterface(binder);
+}
+
+AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
+                                         AIBinder_Class_onTransact onTransact) {
+    AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate,
+                                                  ICInterfaceData::onDestroy, onTransact);
+    if (clazz == nullptr) {
+        return nullptr;
+    }
+
+    // We can't know if this method is overriden by a subclass interface, so we must register
+    // ourselves. The default (nothing to dump) is harmless.
+    AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
+    return clazz;
+}
+
+std::shared_ptr<ICInterface> ICInterface::ICInterfaceData::getInterface(AIBinder* binder) {
+    if (binder == nullptr) return nullptr;
+
+    void* userData = AIBinder_getUserData(binder);
+    if (userData == nullptr) return nullptr;
+
+    return static_cast<ICInterfaceData*>(userData)->interface;
+}
+
+void* ICInterface::ICInterfaceData::onCreate(void* args) {
+    std::shared_ptr<ICInterface> interface = static_cast<ICInterface*>(args)->ref<ICInterface>();
+    ICInterfaceData* data = new ICInterfaceData{interface};
+    return static_cast<void*>(data);
+}
+
+void ICInterface::ICInterfaceData::onDestroy(void* userData) {
+    delete static_cast<ICInterfaceData*>(userData);
+}
+
+binder_status_t ICInterface::ICInterfaceData::onDump(AIBinder* binder, int fd, const char** args,
+                                                     uint32_t numArgs) {
+    std::shared_ptr<ICInterface> interface = getInterface(binder);
+    return interface->dump(fd, args, numArgs);
+}
+
+template <typename INTERFACE>
+SpAIBinder BnCInterface<INTERFACE>::asBinder() {
+    std::lock_guard<std::mutex> l(mMutex);
+
+    SpAIBinder binder;
+    if (mWeakBinder.get() != nullptr) {
+        binder.set(AIBinder_Weak_promote(mWeakBinder.get()));
+    }
+    if (binder.get() == nullptr) {
+        binder = createBinder();
+        mWeakBinder.set(AIBinder_Weak_new(binder.get()));
+    }
+
+    return binder;
+}
+
+template <typename INTERFACE>
+SpAIBinder BpCInterface<INTERFACE>::asBinder() {
+    return mBinder;
+}
+
+}  // namespace ndk
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
new file mode 100644
index 0000000..2258210
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel.h
+ * @brief A collection of data that can be sent as a single packet.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <android/binder_status.h>
+
+struct AIBinder;
+typedef struct AIBinder AIBinder;
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+/**
+ * This object represents a package of data that can be sent between processes. When transacting, an
+ * instance of it is automatically created to be used for the transaction. When two processes use
+ * binder to communicate, they must agree on a format of this parcel to be used in order to transfer
+ * data. This is usually done in an IDL (see AIDL, specificially).
+ */
+struct AParcel;
+typedef struct AParcel AParcel;
+
+/**
+ * Cleans up a parcel.
+ *
+ * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
+ * transaction is being aborted.
+ */
+void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
+
+/**
+ * Sets the position within the parcel.
+ *
+ * \param parcel The parcel of which to set the position.
+ * \param position Position of the parcel to set. This must be a value returned by
+ * AParcel_getDataPosition. Positions are constant for a given parcel between processes.
+ *
+ * \return STATUS_OK on success. If position is negative, then STATUS_BAD_VALUE will be returned.
+ */
+binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position)
+        __INTRODUCED_IN(29);
+
+/**
+ * Gets the current position within the parcel.
+ *
+ * \param parcel The parcel of which to get the position.
+ *
+ * \return The size of the parcel. This will always be greater than 0. The values returned by this
+ * function before and after calling various reads and writes are not defined. Only the delta
+ * between two positions between a specific sequence of calls is defined. For instance, if position
+ * is X, writeBool is called, and then position is Y, readBool can be called from position X will
+ * return the same value, and then position will be Y.
+ */
+int32_t AParcel_getDataPosition(const AParcel* parcel) __INTRODUCED_IN(29);
+
+/**
+ * This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer
+ * should be at least length bytes. This includes space for a null terminator. For a string, length
+ * will always be strictly less than or equal to the maximum size that can be held in a size_t and
+ * will always be greater than 0. However, if a 'null' string is being read, length will be -1.
+ *
+ * See also AParcel_readString.
+ *
+ * If allocation fails, null should be returned.
+ *
+ * \param stringData some external representation of a string
+ * \param length the length of the buffer needed to fill (including the null-terminator)
+ * \param buffer a buffer of size 'length' or null if allocation failed.
+ *
+ * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here
+ * means that a 'null' value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, char** buffer);
+
+/**
+ * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or
+ * equivalent) should be created.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded. If length is -1, a true return here means that a 'null'
+ * value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, int32_t length);
+
+/**
+ * This is called to allocate a string inside of an array that was allocated by an
+ * AParcel_stringArrayAllocator.
+ *
+ * The index returned will always be within the range [0, length of arrayData). The returned buffer
+ * should be at least length bytes. This includes space for a null-terminator. For a string, length
+ * will always be strictly less than or equal to the maximum size that can be held in a size_t and
+ * will always be greater than 0. However, if a 'null' string is being read, length will be -1.
+ *
+ * See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param length the length of the string to be allocated at this index. See also
+ * AParcel_stringAllocator. This includes the length required for a null-terminator.
+ * \param buffer a buffer of size 'length' or null if allocation failed.
+ *
+ * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here
+ * means that a 'null' value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, int32_t length,
+                                                    char** buffer);
+
+/**
+ * This returns the length and buffer of an array at a specific index in an arrayData object.
+ *
+ * See also AParcel_writeStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param outLength an out parameter for the length of the string at the specified index. This
+ * should not include the length for a null-terminator if there is one. If the object at this index
+ * is 'null', then this should be set to -1.
+ *
+ * \param a buffer of size outLength or more representing the string at the provided index. This is
+ * not required to be null-terminated. If the object at index is null, then this should be null.
+ */
+typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
+                                                        int32_t* outLength);
+
+/**
+ * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or
+ * equivalent) should be created.
+ *
+ * See also AParcel_readParcelableArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded. If length is -1, a true return here means that a 'null'
+ * value (or equivalent) was successfully stored.
+ */
+typedef bool (*AParcel_parcelableArrayAllocator)(void* arrayData, int32_t length);
+
+/**
+ * This is called to parcel the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeParcelableArray
+ *
+ * \param parcel parcel to write the parcelable to
+ * \param arrayData some external representation of an array of parcelables (a user-defined type).
+ * \param index the index of the value to be retrieved.
+ *
+ * \return status (usually returned from other parceling functions). STATUS_OK for success.
+ */
+typedef binder_status_t (*AParcel_writeParcelableElement)(AParcel* parcel, const void* arrayData,
+                                                          size_t index);
+
+/**
+ * This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readParcelableArray
+ *
+ * \param parcel parcel to read the parcelable from
+ * \param arrayData some external representation of an array of parcelables (a user-defined type).
+ * \param index the index of the value to be set.
+ *
+ * \return status (usually returned from other parceling functions). STATUS_OK for success.
+ */
+typedef binder_status_t (*AParcel_readParcelableElement)(const AParcel* parcel, void* arrayData,
+                                                         size_t index);
+
+// @START-PRIMITIVE-VECTOR-GETTERS
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readInt32Array
+ *
+ * \param arrayData some external representation of an array of int32_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int32_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_int32ArrayAllocator)(void* arrayData, int32_t length, int32_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readUint32Array
+ *
+ * \param arrayData some external representation of an array of uint32_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of uint32_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_uint32ArrayAllocator)(void* arrayData, int32_t length, uint32_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readInt64Array
+ *
+ * \param arrayData some external representation of an array of int64_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int64_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_int64ArrayAllocator)(void* arrayData, int32_t length, int64_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readUint64Array
+ *
+ * \param arrayData some external representation of an array of uint64_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of uint64_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_uint64ArrayAllocator)(void* arrayData, int32_t length, uint64_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readFloatArray
+ *
+ * \param arrayData some external representation of an array of float.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of float of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_floatArrayAllocator)(void* arrayData, int32_t length, float** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readDoubleArray
+ *
+ * \param arrayData some external representation of an array of double.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of double of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_doubleArrayAllocator)(void* arrayData, int32_t length, double** outBuffer);
+
+/**
+ * This allocates an array of size 'length' inside of arrayData and returns whether or not there was
+ * a success. If length is -1, then this should allocate some representation of a null array.
+ *
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param length the length to allocate arrayData to (or -1 if this represents a null array).
+ *
+ * \return whether the allocation succeeded.
+ */
+typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, int32_t length);
+
+/**
+ * This is called to get the underlying data from an arrayData object at index.
+ *
+ * See also AParcel_writeBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be retrieved.
+ *
+ * \return the value of the array at index index.
+ */
+typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
+
+/**
+ * This is called to set an underlying value in an arrayData object at index.
+ *
+ * See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be set.
+ * \param value the value to set at index index.
+ */
+typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readCharArray
+ *
+ * \param arrayData some external representation of an array of char16_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of char16_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_charArrayAllocator)(void* arrayData, int32_t length, char16_t** outBuffer);
+
+/**
+ * This is called to get the underlying data from an arrayData object.
+ *
+ * The implementation of this function should allocate a contiguous array of size 'length' and
+ * return that underlying buffer to be filled out. If there is an error or length is 0, null may be
+ * returned. If length is -1, this should allocate some representation of a null array.
+ *
+ * See also AParcel_readByteArray
+ *
+ * \param arrayData some external representation of an array of int8_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int8_t of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
+ */
+typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8_t** outBuffer);
+
+// @END-PRIMITIVE-VECTOR-GETTERS
+
+/**
+ * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
+ * refcounts of ownership of the binder from the client.
+ *
+ * \param parcel the parcel to write to.
+ * \param binder the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
+
+/**
+ * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership
+ * is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This may be null.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
+ * of fd.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to write to.
+ * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor).
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
+
+/**
+ * Reads an int from the next location in a non-null parcel.
+ *
+ * The returned fd must be closed.
+ *
+ * This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to read from.
+ * \param fd the out parameter for what is read from the parcel (or -1 to represent a null
+ * ParcelFileDescriptor)
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
+
+/**
+ * Writes an AStatus object to the next location in a non-null parcel.
+ *
+ * If the status is considered to be a low-level status and has no additional information other
+ * than a binder_status_t (for instance, if it is created with AStatus_fromStatus), then that
+ * status will be returned from this method and nothing will be written to the parcel. If either
+ * this happens or if writing the status object itself fails, the return value from this function
+ * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
+ *
+ * \param parcel the parcel to write to.
+ * \param status the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
+ * of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param status the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes utf-8 string value to the next location in a non-null parcel.
+ *
+ * If length is -1, and string is nullptr, this will write a 'null' string to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param string the null-terminated string to write to the parcel, at least of size 'length'.
+ * \param length the length of the string to be written.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads and allocates utf-8 string value from the next location in a non-null parcel.
+ *
+ * Data is passed to the string allocator once the string size is known. This size includes the
+ * space for the null-terminator of this string. This allocator returns a buffer which is used as
+ * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator
+ * will be called with length -1.
+ *
+ * \param parcel the parcel to read from.
+ * \param stringData some external representation of a string.
+ * \param allocator allocator that will be called once the size of the string is known.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+                                   AParcel_stringAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Writes utf-8 string array data to the next location in a non-null parcel.
+ *
+ * length is the length of the array. AParcel_stringArrayElementGetter will be called for all
+ * indices in range [0, length) with the arrayData provided here. The string length and buffer
+ * returned from this function will be used to fill out the data from the parcel. If length is -1,
+ * this will write a 'null' string array to the binder buffer.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of the array to be written.
+ * \param getter the callback that will be called for every index of the array to retrieve the
+ * corresponding string buffer.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                         AParcel_stringArrayElementGetter getter)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads and allocates utf-8 string array value from the next location in a non-null parcel.
+ *
+ * First, AParcel_stringArrayAllocator will be called with the size of the array to be read where
+ * length is the length of the array to be read from the parcel. Then, for each index i in [0,
+ * length), AParcel_stringArrayElementAllocator will be called with the length of the string to be
+ * read from the parcel. The resultant buffer from each of these calls will be filled according to
+ * the contents of the string that is read. If the string array being read is 'null', this will
+ * instead just pass -1 to AParcel_stringArrayAllocator.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called with arrayData once the size of the output
+ * array is known.
+ * \param elementAllocator the callback that will be called on every index of arrayData to allocate
+ * the string at that location.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_stringArrayAllocator allocator,
+                                        AParcel_stringArrayElementAllocator elementAllocator)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ * \param elementWriter function to be called for every array index to write the user-defined type
+ * at that location.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                             AParcel_writeParcelableElement elementWriter)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of parcelables (user-defined types) from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, elementReader will be called for every index to read the
+ * corresponding parcelable.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param elementReader the callback that will be called to fill out individual elements.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
+                                            AParcel_parcelableArrayAllocator allocator,
+                                            AParcel_readParcelableElement elementReader)
+        __INTRODUCED_IN(29);
+
+// @START-PRIMITIVE-READ-WRITE
+/**
+ * Writes int32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29);
+
+/**
+ * Writes uint32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29);
+
+/**
+ * Writes int64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29);
+
+/**
+ * Writes uint64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29);
+
+/**
+ * Writes float value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29);
+
+/**
+ * Writes double value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29);
+
+/**
+ * Writes bool value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29);
+
+/**
+ * Writes char16_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29);
+
+/**
+ * Writes int8_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into int32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into uint32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into int64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into uint64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into float value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into double value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into bool value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into char16_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29);
+
+/**
+ * Reads into int8_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of uint32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of uint64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of float to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of double to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of bool to the next location in a non-null parcel.
+ *
+ * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
+ * values to write to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of arrayData (or -1 if this represents a null array).
+ * \param getter the callback to retrieve data at specific locations in the array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                       AParcel_boolArrayGetter getter) __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of char16_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Writes an array of int8_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
+ */
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length)
+        __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int32ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of uint32_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint32ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int64ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of uint64_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint64ArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of float from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+                                       AParcel_floatArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of double from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_doubleArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of bool from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. Then, for every i in [0, length),
+ * setter(arrayData, i, x) will be called where x is the value at the associated index.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param setter the callback that will be called to set a value at a specific location in the
+ * array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_boolArrayAllocator allocator,
+                                      AParcel_boolArraySetter setter) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of char16_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_charArrayAllocator allocator) __INTRODUCED_IN(29);
+
+/**
+ * Reads an array of int8_t from the next location in a non-null parcel.
+ *
+ * First, allocator will be called with the length of the array. If the allocation succeeds and the
+ * length is greater than zero, the buffer returned by the allocator will be filled with the
+ * corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
+ */
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_byteArrayAllocator allocator) __INTRODUCED_IN(29);
+
+// @END-PRIMITIVE-READ-WRITE
+
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
new file mode 100644
index 0000000..f3bc31b
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -0,0 +1,837 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel_utils.h
+ * @brief A collection of helper wrappers for AParcel.
+ */
+
+#pragma once
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_parcel.h>
+
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace ndk {
+
+/**
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
+ */
+template <typename T>
+static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) {
+    if (length < 0) return false;
+
+    std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+    if (static_cast<size_t>(length) > vec->max_size()) return false;
+
+    vec->resize(length);
+    *outBuffer = vec->data();
+    return true;
+}
+
+/**
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
+ */
+template <typename T>
+static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length,
+                                                      T** outBuffer) {
+    std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+
+    if (length < 0) {
+        *vec = std::nullopt;
+        return true;
+    }
+
+    *vec = std::optional<std::vector<T>>(std::vector<T>{});
+
+    if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
+    (*vec)->resize(length);
+
+    *outBuffer = (*vec)->data();
+    return true;
+}
+
+/**
+ * This allocates a vector to size 'length' and returns whether the allocation is successful.
+ *
+ * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
+ * externally with respect to the NDK, and that size information is not passed into the NDK.
+ * Instead, it is used in cases where callbacks are used. Note that when this allocator is used,
+ * null arrays are not supported.
+ *
+ * See AParcel_readVector(const AParcel* parcel, std::vector<bool>)
+ * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>)
+ */
+template <typename T>
+static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) {
+    if (length < 0) return false;
+
+    std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+    if (static_cast<size_t>(length) > vec->max_size()) return false;
+
+    vec->resize(length);
+    return true;
+}
+
+/**
+ * This allocates a vector to size 'length' and returns whether the allocation is successful.
+ *
+ * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
+ * externally with respect to the NDK, and that size information is not passed into the NDK.
+ * Instead, it is used in cases where callbacks are used. Note, when this allocator is used,
+ * the vector itself can be nullable.
+ *
+ * See AParcel_readVector(const AParcel* parcel,
+ * std::optional<std::vector<std::optional<std::string>>>)
+ */
+template <typename T>
+static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) {
+    std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+
+    if (length < 0) {
+        *vec = std::nullopt;
+        return true;
+    }
+
+    *vec = std::optional<std::vector<T>>(std::vector<T>{});
+
+    if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
+    (*vec)->resize(length);
+
+    return true;
+}
+
+/**
+ * This retrieves the underlying value in a vector which may not be contiguous at index from a
+ * corresponding vectorData.
+ */
+template <typename T>
+static inline T AParcel_stdVectorGetter(const void* vectorData, size_t index) {
+    const std::vector<T>* vec = static_cast<const std::vector<T>*>(vectorData);
+    return (*vec)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding vectorData which may not be contiguous at
+ * index.
+ */
+template <typename T>
+static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T value) {
+    std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
+    (*vec)[index] = value;
+}
+
+/**
+ * This sets the underlying value in a corresponding vectorData which may not be contiguous at
+ * index.
+ */
+template <typename T>
+static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) {
+    std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+    vec->value()[index] = value;
+}
+
+/**
+ * Convenience method to write a nullable strong binder.
+ */
+static inline binder_status_t AParcel_writeNullableStrongBinder(AParcel* parcel,
+                                                                const SpAIBinder& binder) {
+    return AParcel_writeStrongBinder(parcel, binder.get());
+}
+
+/**
+ * Convenience method to read a nullable strong binder.
+ */
+static inline binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel,
+                                                               SpAIBinder* binder) {
+    AIBinder* readBinder;
+    binder_status_t status = AParcel_readStrongBinder(parcel, &readBinder);
+    if (status == STATUS_OK) {
+        binder->set(readBinder);
+    }
+    return status;
+}
+
+/**
+ * Convenience method to write a strong binder but return an error if it is null.
+ */
+static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel,
+                                                                const SpAIBinder& binder) {
+    if (binder.get() == nullptr) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+    return AParcel_writeStrongBinder(parcel, binder.get());
+}
+
+/**
+ * Convenience method to read a strong binder but return an error if it is null.
+ */
+static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* parcel,
+                                                               SpAIBinder* binder) {
+    AIBinder* readBinder;
+    binder_status_t ret = AParcel_readStrongBinder(parcel, &readBinder);
+    if (ret == STATUS_OK) {
+        if (readBinder == nullptr) {
+            return STATUS_UNEXPECTED_NULL;
+        }
+
+        binder->set(readBinder);
+    }
+    return ret;
+}
+
+/**
+ * Convenience method to write a ParcelFileDescriptor where -1 represents a null value.
+ */
+static inline binder_status_t AParcel_writeNullableParcelFileDescriptor(
+        AParcel* parcel, const ScopedFileDescriptor& fd) {
+    return AParcel_writeParcelFileDescriptor(parcel, fd.get());
+}
+
+/**
+ * Convenience method to read a ParcelFileDescriptor where -1 represents a null value.
+ */
+static inline binder_status_t AParcel_readNullableParcelFileDescriptor(const AParcel* parcel,
+                                                                       ScopedFileDescriptor* fd) {
+    int readFd;
+    binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
+    if (status == STATUS_OK) {
+        fd->set(readFd);
+    }
+    return status;
+}
+
+/**
+ * Convenience method to write a valid ParcelFileDescriptor.
+ */
+static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor(
+        AParcel* parcel, const ScopedFileDescriptor& fd) {
+    if (fd.get() < 0) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+    return AParcel_writeParcelFileDescriptor(parcel, fd.get());
+}
+
+/**
+ * Convenience method to read a valid ParcelFileDescriptor.
+ */
+static inline binder_status_t AParcel_readRequiredParcelFileDescriptor(const AParcel* parcel,
+                                                                       ScopedFileDescriptor* fd) {
+    int readFd;
+    binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
+    if (status == STATUS_OK) {
+        if (readFd < 0) {
+            return STATUS_UNEXPECTED_NULL;
+        }
+        fd->set(readFd);
+    }
+    return status;
+}
+
+/**
+ * Allocates a std::string to length and returns the underlying buffer. For use with
+ * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*).
+ */
+static inline bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) {
+    if (length <= 0) return false;
+
+    std::string* str = static_cast<std::string*>(stringData);
+    str->resize(length - 1);
+    *buffer = &(*str)[0];
+    return true;
+}
+
+/**
+ * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when
+ * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below
+ * in AParcel_readString(const AParcel*, std::optional<std::string>*).
+ */
+static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length,
+                                                      char** buffer) {
+    if (length == 0) return false;
+
+    std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData);
+
+    if (length < 0) {
+        *str = std::nullopt;
+        return true;
+    }
+
+    *str = std::optional<std::string>(std::string{});
+    (*str)->resize(length - 1);
+    *buffer = &(**str)[0];
+    return true;
+}
+
+/**
+ * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'.
+ */
+static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
+                                                           int32_t length, char** buffer) {
+    std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
+    std::string& element = vec->at(index);
+    return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a std::vector<std::string> at index
+ * index.
+ */
+static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index,
+                                                               int32_t* outLength) {
+    const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
+    const std::string& element = vec->at(index);
+
+    *outLength = element.size();
+    return element.c_str();
+}
+
+/**
+ * Allocates a string in a std::optional<std::string> inside of a
+ * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to
+ * std::nullopt when length is -1).
+ */
+static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index,
+                                                                   int32_t length, char** buffer) {
+    std::optional<std::vector<std::optional<std::string>>>* vec =
+            static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
+    std::optional<std::string>& element = vec->value().at(index);
+    return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::optional<std::string> inside of a
+ * std::vector<std::string> at index index. If the string is null, then it returns null and a length
+ * of -1.
+ */
+static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData,
+                                                                       size_t index,
+                                                                       int32_t* outLength) {
+    const std::optional<std::vector<std::optional<std::string>>>* vec =
+            static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
+    const std::optional<std::string>& element = vec->value().at(index);
+
+    if (!element) {
+        *outLength = -1;
+        return nullptr;
+    }
+
+    *outLength = element->size();
+    return element->c_str();
+}
+
+/**
+ * Convenience API for writing a std::string.
+ */
+static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
+    return AParcel_writeString(parcel, str.c_str(), str.size());
+}
+
+/**
+ * Convenience API for reading a std::string.
+ */
+static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
+    void* stringData = static_cast<void*>(str);
+    return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator);
+}
+
+/**
+ * Convenience API for writing a std::optional<std::string>.
+ */
+static inline binder_status_t AParcel_writeString(AParcel* parcel,
+                                                  const std::optional<std::string>& str) {
+    if (!str) {
+        return AParcel_writeString(parcel, nullptr, -1);
+    }
+
+    return AParcel_writeString(parcel, str->c_str(), str->size());
+}
+
+/**
+ * Convenience API for reading a std::optional<std::string>.
+ */
+static inline binder_status_t AParcel_readString(const AParcel* parcel,
+                                                 std::optional<std::string>* str) {
+    void* stringData = static_cast<void*>(str);
+    return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator);
+}
+
+/**
+ * Convenience API for writing a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                                  const std::vector<std::string>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+                                    AParcel_stdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::vector<std::string>
+ */
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                                 std::vector<std::string>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readStringArray(parcel, vectorData,
+                                   AParcel_stdVectorExternalAllocator<std::string>,
+                                   AParcel_stdVectorStringElementAllocator);
+}
+
+/**
+ * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>>
+ */
+static inline binder_status_t AParcel_writeVector(
+        AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1),
+                                    AParcel_nullableStdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>>
+ */
+static inline binder_status_t AParcel_readVector(
+        const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readStringArray(
+            parcel, vectorData,
+            AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>,
+            AParcel_nullableStdVectorStringElementAllocator);
+}
+
+/**
+ * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData,
+                                                        size_t index) {
+    const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData);
+    return vector->at(index).writeToParcel(parcel);
+}
+
+/**
+ * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData,
+                                                       size_t index) {
+    std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData);
+    return vector->at(index).readFromParcel(parcel);
+}
+
+/**
+ * Convenience API for writing a std::vector<P>
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeParcelableArray(parcel, vectorData, vec.size(),
+                                        AParcel_writeStdVectorParcelableElement<P>);
+}
+
+/**
+ * Convenience API for reading a std::vector<P>
+ */
+template <typename P>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readParcelableArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<P>,
+                                       AParcel_readStdVectorParcelableElement<P>);
+}
+
+// @START
+/**
+ * Writes a vector of int32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
+    return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<int32_t>>& vec) {
+    if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
+}
+
+/**
+ * Reads an optional vector of int32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<int32_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>);
+}
+
+/**
+ * Writes a vector of uint32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
+    return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of uint32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<uint32_t>>& vec) {
+    if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of uint32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
+}
+
+/**
+ * Reads an optional vector of uint32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<uint32_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readUint32Array(parcel, vectorData,
+                                   AParcel_nullableStdVectorAllocator<uint32_t>);
+}
+
+/**
+ * Writes a vector of int64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
+    return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<int64_t>>& vec) {
+    if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
+}
+
+/**
+ * Reads an optional vector of int64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<int64_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>);
+}
+
+/**
+ * Writes a vector of uint64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
+    return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of uint64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<uint64_t>>& vec) {
+    if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of uint64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Reads an optional vector of uint64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<uint64_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readUint64Array(parcel, vectorData,
+                                   AParcel_nullableStdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Writes a vector of float to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
+    return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of float to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<float>>& vec) {
+    if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of float from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
+}
+
+/**
+ * Reads an optional vector of float from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<float>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>);
+}
+
+/**
+ * Writes a vector of double to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
+    return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of double to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<double>>& vec) {
+    if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of double from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
+}
+
+/**
+ * Reads an optional vector of double from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<double>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<double>);
+}
+
+/**
+ * Writes a vector of bool to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
+    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
+                                  AParcel_stdVectorGetter<bool>);
+}
+
+/**
+ * Writes an optional vector of bool to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<bool>>& vec) {
+    if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of bool from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>,
+                                 AParcel_stdVectorSetter<bool>);
+}
+
+/**
+ * Reads an optional vector of bool from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<bool>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readBoolArray(parcel, vectorData,
+                                 AParcel_nullableStdVectorExternalAllocator<bool>,
+                                 AParcel_nullableStdVectorSetter<bool>);
+}
+
+/**
+ * Writes a vector of char16_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
+    return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of char16_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<char16_t>>& vec) {
+    if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of char16_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
+}
+
+/**
+ * Reads an optional vector of char16_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<char16_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>);
+}
+
+/**
+ * Writes a vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
+    return AParcel_writeByteArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                           const std::optional<std::vector<int8_t>>& vec) {
+    if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1);
+    return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int8_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
+}
+
+/**
+ * Reads an optional vector of int8_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                          std::optional<std::vector<int8_t>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>);
+}
+
+// @END
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
+    if (vec.size() > INT32_MAX) {
+        return STATUS_BAD_VALUE;
+    }
+
+    return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
+}
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel,
+                                                      const std::optional<std::vector<T>>& vec) {
+    if (!vec) {
+        return AParcel_writeInt32(parcel, -1);
+    }
+
+    if (vec->size() > INT32_MAX) {
+        return STATUS_BAD_VALUE;
+    }
+
+    return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size()));
+}
+
+/**
+ * Convenience API for resizing a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
+    int32_t size;
+    binder_status_t err = AParcel_readInt32(parcel, &size);
+
+    if (err != STATUS_OK) return err;
+    if (size < 0) return STATUS_UNEXPECTED_NULL;
+
+    vec->resize(static_cast<size_t>(size));
+    return STATUS_OK;
+}
+
+/**
+ * Convenience API for resizing a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_resizeVector(const AParcel* parcel,
+                                                   std::optional<std::vector<T>>* vec) {
+    int32_t size;
+    binder_status_t err = AParcel_readInt32(parcel, &size);
+
+    if (err != STATUS_OK) return err;
+    if (size < -1) return STATUS_UNEXPECTED_NULL;
+
+    if (size == -1) {
+        *vec = std::nullopt;
+        return STATUS_OK;
+    }
+
+    *vec = std::optional<std::vector<T>>(std::vector<T>{});
+    (*vec)->resize(static_cast<size_t>(size));
+    return STATUS_OK;
+}
+
+}  // namespace ndk
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
new file mode 100644
index 0000000..2671b9b
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_status.h
+ */
+
+#pragma once
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+enum {
+    STATUS_OK = 0,
+
+    STATUS_UNKNOWN_ERROR = (-2147483647 - 1),  // INT32_MIN value
+    STATUS_NO_MEMORY = -ENOMEM,
+    STATUS_INVALID_OPERATION = -ENOSYS,
+    STATUS_BAD_VALUE = -EINVAL,
+    STATUS_BAD_TYPE = (STATUS_UNKNOWN_ERROR + 1),
+    STATUS_NAME_NOT_FOUND = -ENOENT,
+    STATUS_PERMISSION_DENIED = -EPERM,
+    STATUS_NO_INIT = -ENODEV,
+    STATUS_ALREADY_EXISTS = -EEXIST,
+    STATUS_DEAD_OBJECT = -EPIPE,
+    STATUS_FAILED_TRANSACTION = (STATUS_UNKNOWN_ERROR + 2),
+    STATUS_BAD_INDEX = -EOVERFLOW,
+    STATUS_NOT_ENOUGH_DATA = -ENODATA,
+    STATUS_WOULD_BLOCK = -EWOULDBLOCK,
+    STATUS_TIMED_OUT = -ETIMEDOUT,
+    STATUS_UNKNOWN_TRANSACTION = -EBADMSG,
+    STATUS_FDS_NOT_ALLOWED = (STATUS_UNKNOWN_ERROR + 7),
+    STATUS_UNEXPECTED_NULL = (STATUS_UNKNOWN_ERROR + 8),
+};
+
+/**
+ * One of the STATUS_* values.
+ *
+ * All unrecognized values are coerced into STATUS_UNKNOWN_ERROR.
+ */
+typedef int32_t binder_status_t;
+
+enum {
+    EX_NONE = 0,
+    EX_SECURITY = -1,
+    EX_BAD_PARCELABLE = -2,
+    EX_ILLEGAL_ARGUMENT = -3,
+    EX_NULL_POINTER = -4,
+    EX_ILLEGAL_STATE = -5,
+    EX_NETWORK_MAIN_THREAD = -6,
+    EX_UNSUPPORTED_OPERATION = -7,
+    EX_SERVICE_SPECIFIC = -8,
+    EX_PARCELABLE = -9,
+
+    /**
+     * This is special, and indicates to native binder proxies that the
+     * transaction has failed at a low level.
+     */
+    EX_TRANSACTION_FAILED = -129,
+};
+
+/**
+ * One of the EXCEPTION_* types.
+ *
+ * All unrecognized values are coerced into EXCEPTION_TRANSACTION_FAILED.
+ *
+ * These exceptions values are used by the SDK for parcelables. Also see Parcel.java.
+ */
+typedef int32_t binder_exception_t;
+
+/**
+ * This is a helper class that encapsulates a standard way to keep track of and chain binder errors
+ * along with service specific errors.
+ *
+ * It is not required to be used in order to parcel/receive transactions, but it is required in
+ * order to be compatible with standard AIDL transactions since it is written as the header to the
+ * out parcel for transactions which get executed (don't fail during unparceling of input arguments
+ * or sooner).
+ */
+struct AStatus;
+typedef struct AStatus AStatus;
+
+/**
+ * New status which is considered a success.
+ *
+ * \return a newly constructed status object that the caller owns.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
+
+/**
+ * New status with exception code.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ *
+ * \return a newly constructed status object that the caller owns.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception)
+        __INTRODUCED_IN(29);
+
+/**
+ * New status with exception code and message.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
+        binder_exception_t exception, const char* message) __INTRODUCED_IN(29);
+
+/**
+ * New status with a service speciic error.
+ *
+ * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ *
+ * \return a newly constructed status object that the caller owns.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
+        int32_t serviceSpecific) __INTRODUCED_IN(29);
+
+/**
+ * New status with a service specific error and message.
+ *
+ * This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
+        int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29);
+
+/**
+ * New status with binder_status_t. This is typically for low level failures when a binder_status_t
+ * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
+ * an AStatus instance.
+ *
+ * \param a low-level error to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
+ */
+__attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status)
+        __INTRODUCED_IN(29);
+
+/**
+ * Whether this object represents a successful transaction. If this function returns true, then
+ * AStatus_getExceptionCode will return EX_NONE.
+ *
+ * \param status the status being queried.
+ *
+ * \return whether the status represents a successful transaction. For more details, see below.
+ */
+bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29);
+
+/**
+ * The exception that this status object represents.
+ *
+ * \param status the status being queried.
+ *
+ * \return the exception code that this object represents.
+ */
+binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29);
+
+/**
+ * The service specific error if this object represents one. This function will only ever return a
+ * non-zero result if AStatus_getExceptionCode returns EX_SERVICE_SPECIFIC. If this function returns
+ * 0, the status object may still represent a different exception or status. To find out if this
+ * transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
+ */
+int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29);
+
+/**
+ * The status if this object represents one. This function will only ever return a non-zero result
+ * if AStatus_getExceptionCode returns EX_TRANSACTION_FAILED. If this function return 0, the status
+ * object may represent a different exception or a service specific error. To find out if this
+ * transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
+ */
+binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29);
+
+/**
+ * If there is a message associated with this status, this will return that message. If there is no
+ * message, this will return an empty string.
+ *
+ * The returned string has the lifetime of the status object passed into this function.
+ *
+ * \param status the status being queried.
+ *
+ * \return the message associated with this error.
+ */
+const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
+
+/**
+ * Deletes memory associated with the status instance.
+ *
+ * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
+ */
+void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
+
+#endif  //__ANDROID_API__ >= __ANDROID_API_Q__
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
new file mode 100644
index 0000000..7e65817
--- /dev/null
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -0,0 +1,100 @@
+LIBBINDER_NDK { # introduced=29
+  global:
+    AIBinder_associateClass;
+    AIBinder_Class_define;
+    AIBinder_Class_setOnDump;
+    AIBinder_DeathRecipient_delete;
+    AIBinder_DeathRecipient_new;
+    AIBinder_debugGetRefCount;
+    AIBinder_decStrong;
+    AIBinder_dump;
+    AIBinder_fromJavaBinder;
+    AIBinder_getCallingPid;
+    AIBinder_getCallingUid;
+    AIBinder_getClass;
+    AIBinder_getUserData;
+    AIBinder_incStrong;
+    AIBinder_isAlive;
+    AIBinder_isRemote;
+    AIBinder_linkToDeath;
+    AIBinder_new;
+    AIBinder_ping;
+    AIBinder_prepareTransaction;
+    AIBinder_toJavaBinder;
+    AIBinder_transact;
+    AIBinder_unlinkToDeath;
+    AIBinder_Weak_delete;
+    AIBinder_Weak_new;
+    AIBinder_Weak_promote;
+    AParcel_delete;
+    AParcel_getDataPosition;
+    AParcel_readBool;
+    AParcel_readBoolArray;
+    AParcel_readByte;
+    AParcel_readByteArray;
+    AParcel_readChar;
+    AParcel_readCharArray;
+    AParcel_readDouble;
+    AParcel_readDoubleArray;
+    AParcel_readFloat;
+    AParcel_readFloatArray;
+    AParcel_readInt32;
+    AParcel_readInt32Array;
+    AParcel_readInt64;
+    AParcel_readInt64Array;
+    AParcel_readParcelableArray;
+    AParcel_readParcelFileDescriptor;
+    AParcel_readStatusHeader;
+    AParcel_readString;
+    AParcel_readStringArray;
+    AParcel_readStrongBinder;
+    AParcel_readUint32;
+    AParcel_readUint32Array;
+    AParcel_readUint64;
+    AParcel_readUint64Array;
+    AParcel_setDataPosition;
+    AParcel_writeBool;
+    AParcel_writeBoolArray;
+    AParcel_writeByte;
+    AParcel_writeByteArray;
+    AParcel_writeChar;
+    AParcel_writeCharArray;
+    AParcel_writeDouble;
+    AParcel_writeDoubleArray;
+    AParcel_writeFloat;
+    AParcel_writeFloatArray;
+    AParcel_writeInt32;
+    AParcel_writeInt32Array;
+    AParcel_writeInt64;
+    AParcel_writeInt64Array;
+    AParcel_writeParcelableArray;
+    AParcel_writeParcelFileDescriptor;
+    AParcel_writeStatusHeader;
+    AParcel_writeString;
+    AParcel_writeStringArray;
+    AParcel_writeStrongBinder;
+    AParcel_writeUint32;
+    AParcel_writeUint32Array;
+    AParcel_writeUint64;
+    AParcel_writeUint64Array;
+    AStatus_delete;
+    AStatus_fromExceptionCode;
+    AStatus_fromExceptionCodeWithMessage;
+    AStatus_fromServiceSpecificError;
+    AStatus_fromServiceSpecificErrorWithMessage;
+    AStatus_fromStatus;
+    AStatus_getExceptionCode;
+    AStatus_getMessage;
+    AStatus_getServiceSpecificError;
+    AStatus_getStatus;
+    AStatus_isOk;
+    AStatus_newOk;
+    ABinderProcess_joinThreadPool; # apex
+    ABinderProcess_setThreadPoolMaxThreadCount; # apex
+    ABinderProcess_startThreadPool; # apex
+    AServiceManager_addService; # apex
+    AServiceManager_checkService; # apex
+    AServiceManager_getService; # apex
+  local:
+    *;
+};
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
new file mode 100644
index 0000000..ae2276e
--- /dev/null
+++ b/libs/binder/ndk/parcel.cpp
@@ -0,0 +1,653 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_parcel.h>
+#include "parcel_internal.h"
+
+#include "ibinder_internal.h"
+#include "status_internal.h"
+
+#include <limits>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <utils/Unicode.h>
+
+using ::android::IBinder;
+using ::android::Parcel;
+using ::android::sp;
+using ::android::status_t;
+using ::android::base::unique_fd;
+using ::android::os::ParcelFileDescriptor;
+
+template <typename T>
+using ContiguousArrayAllocator = bool (*)(void* arrayData, int32_t length, T** outBuffer);
+
+template <typename T>
+using ArrayAllocator = bool (*)(void* arrayData, int32_t length);
+template <typename T>
+using ArrayGetter = T (*)(const void* arrayData, size_t index);
+template <typename T>
+using ArraySetter = void (*)(void* arrayData, size_t index, T value);
+
+binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int32_t length) {
+    // only -1 can be used to represent a null array
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!isNullArray && length < 0) {
+        LOG(ERROR) << __func__ << ": null array must be used with length == -1.";
+        return STATUS_BAD_VALUE;
+    }
+    if (isNullArray && length > 0) {
+        LOG(ERROR) << __func__ << ": null buffer cannot be for size " << length << " array.";
+        return STATUS_BAD_VALUE;
+    }
+
+    Parcel* rawParcel = parcel->get();
+
+    status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+    if (status != STATUS_OK) return PruneStatusT(status);
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const T* array, int32_t length) {
+    binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
+
+    void* const data = parcel->get()->writeInplace(size);
+    if (data == nullptr) return STATUS_NO_MEMORY;
+
+    memcpy(data, array, size);
+
+    return STATUS_OK;
+}
+
+// Each element in a char16_t array is converted to an int32_t (not packed).
+template <>
+binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, int32_t length) {
+    binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+
+    Parcel* rawParcel = parcel->get();
+
+    for (int32_t i = 0; i < length; i++) {
+        status = rawParcel->writeChar(array[i]);
+
+        if (status != STATUS_OK) return PruneStatusT(status);
+    }
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData,
+                          ContiguousArrayAllocator<T> allocator) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    T* array;
+    if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+    if (length <= 0) return STATUS_OK;
+    if (array == nullptr) return STATUS_NO_MEMORY;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
+
+    const void* data = rawParcel->readInplace(size);
+    if (data == nullptr) return STATUS_NO_MEMORY;
+
+    memcpy(array, data, size);
+
+    return STATUS_OK;
+}
+
+// Each element in a char16_t array is converted to an int32_t (not packed)
+template <>
+binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData,
+                                    ContiguousArrayAllocator<char16_t> allocator) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    char16_t* array;
+    if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+    if (length <= 0) return STATUS_OK;
+    if (array == nullptr) return STATUS_NO_MEMORY;
+
+    int32_t size = 0;
+    if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+
+    for (int32_t i = 0; i < length; i++) {
+        status = rawParcel->readChar(array + i);
+
+        if (status != STATUS_OK) return PruneStatusT(status);
+    }
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, int32_t length,
+                           ArrayGetter<T> getter, status_t (Parcel::*write)(T)) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    Parcel* rawParcel = parcel->get();
+
+    for (int32_t i = 0; i < length; i++) {
+        status = (rawParcel->*write)(getter(arrayData, i));
+
+        if (status != STATUS_OK) return PruneStatusT(status);
+    }
+
+    return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t ReadArray(const AParcel* parcel, void* arrayData, ArrayAllocator<T> allocator,
+                          ArraySetter<T> setter, status_t (Parcel::*read)(T*) const) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        T readTarget;
+        status = (rawParcel->*read)(&readTarget);
+        if (status != STATUS_OK) return PruneStatusT(status);
+
+        setter(arrayData, i, readTarget);
+    }
+
+    return STATUS_OK;
+}
+
+void AParcel_delete(AParcel* parcel) {
+    delete parcel;
+}
+
+binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) {
+    if (position < 0) {
+        return STATUS_BAD_VALUE;
+    }
+
+    parcel->get()->setDataPosition(position);
+    return STATUS_OK;
+}
+
+int32_t AParcel_getDataPosition(const AParcel* parcel) {
+    return parcel->get()->dataPosition();
+}
+
+binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
+    sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr;
+    return parcel->get()->writeStrongBinder(writeBinder);
+}
+binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
+    sp<IBinder> readBinder = nullptr;
+    status_t status = parcel->get()->readNullableStrongBinder(&readBinder);
+    if (status != STATUS_OK) {
+        return PruneStatusT(status);
+    }
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
+    AIBinder_incStrong(ret.get());
+    *binder = ret.get();
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
+    std::unique_ptr<ParcelFileDescriptor> parcelFd;
+
+    if (fd < 0) {
+        if (fd != -1) {
+            return STATUS_UNKNOWN_ERROR;
+        }
+        // parcelFd = nullptr
+    } else {  // fd >= 0
+        parcelFd = std::make_unique<ParcelFileDescriptor>(unique_fd(fd));
+    }
+
+    status_t status = parcel->get()->writeNullableParcelable(parcelFd);
+
+    // ownership is retained by caller
+    if (parcelFd != nullptr) {
+        (void)parcelFd->release().release();
+    }
+
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
+    std::unique_ptr<ParcelFileDescriptor> parcelFd;
+
+    status_t status = parcel->get()->readParcelable(&parcelFd);
+    if (status != STATUS_OK) return PruneStatusT(status);
+
+    if (parcelFd) {
+        *fd = parcelFd->release().release();
+    } else {
+        *fd = -1;
+    }
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
+    return PruneStatusT(status->get()->writeToParcel(parcel->get()));
+}
+binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
+    ::android::binder::Status bstatus;
+    binder_status_t ret = PruneStatusT(bstatus.readFromParcel(*parcel->get()));
+    if (ret == STATUS_OK) {
+        *status = new AStatus(std::move(bstatus));
+    }
+    return PruneStatusT(ret);
+}
+
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) {
+    if (string == nullptr) {
+        if (length != -1) {
+            LOG(WARNING) << __func__ << ": null string must be used with length == -1.";
+            return STATUS_BAD_VALUE;
+        }
+
+        status_t err = parcel->get()->writeInt32(-1);
+        return PruneStatusT(err);
+    }
+
+    if (length < 0) {
+        LOG(WARNING) << __func__ << ": Negative string length: " << length;
+        return STATUS_BAD_VALUE;
+    }
+
+    const uint8_t* str8 = (uint8_t*)string;
+    const ssize_t len16 = utf8_to_utf16_length(str8, length);
+
+    if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) {
+        LOG(WARNING) << __func__ << ": Invalid string length: " << len16;
+        return STATUS_BAD_VALUE;
+    }
+
+    status_t err = parcel->get()->writeInt32(len16);
+    if (err) {
+        return PruneStatusT(err);
+    }
+
+    void* str16 = parcel->get()->writeInplace((len16 + 1) * sizeof(char16_t));
+    if (str16 == nullptr) {
+        return STATUS_NO_MEMORY;
+    }
+
+    utf8_to_utf16(str8, length, (char16_t*)str16, (size_t)len16 + 1);
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
+                                   AParcel_stringAllocator allocator) {
+    size_t len16;
+    const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
+
+    if (str16 == nullptr) {
+        if (allocator(stringData, -1, nullptr)) {
+            return STATUS_OK;
+        }
+
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    ssize_t len8;
+
+    if (len16 == 0) {
+        len8 = 1;
+    } else {
+        len8 = utf16_to_utf8_length(str16, len16) + 1;
+    }
+
+    if (len8 <= 0 || len8 > std::numeric_limits<int32_t>::max()) {
+        LOG(WARNING) << __func__ << ": Invalid string length: " << len8;
+        return STATUS_BAD_VALUE;
+    }
+
+    char* str8;
+    bool success = allocator(stringData, len8, &str8);
+
+    if (!success || str8 == nullptr) {
+        LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
+        return STATUS_NO_MEMORY;
+    }
+
+    utf16_to_utf8(str16, len16, str8, len8);
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                         AParcel_stringArrayElementGetter getter) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        int32_t elementLength = 0;
+        const char* str = getter(arrayData, i, &elementLength);
+        if (str == nullptr && elementLength != -1) return STATUS_BAD_VALUE;
+
+        binder_status_t status = AParcel_writeString(parcel, str, elementLength);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+// This implements AParcel_stringAllocator for a string using an array, index, and element
+// allocator.
+struct StringArrayElementAllocationAdapter {
+    void* arrayData;  // stringData from the NDK
+    int32_t index;    // index into the string array
+    AParcel_stringArrayElementAllocator elementAllocator;
+
+    static bool Allocator(void* stringData, int32_t length, char** buffer) {
+        StringArrayElementAllocationAdapter* adapter =
+                static_cast<StringArrayElementAllocationAdapter*>(stringData);
+        return adapter->elementAllocator(adapter->arrayData, adapter->index, length, buffer);
+    }
+};
+
+binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_stringArrayAllocator allocator,
+                                        AParcel_stringArrayElementAllocator elementAllocator) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length == -1) return STATUS_OK;  // null string array
+
+    StringArrayElementAllocationAdapter adapter{
+            .arrayData = arrayData,
+            .index = 0,
+            .elementAllocator = elementAllocator,
+    };
+
+    for (; adapter.index < length; adapter.index++) {
+        binder_status_t status = AParcel_readString(parcel, static_cast<void*>(&adapter),
+                                                    StringArrayElementAllocationAdapter::Allocator);
+
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                             AParcel_writeParcelableElement elementWriter) {
+    // we have no clue if arrayData represents a null object or not, we can only infer from length
+    bool arrayIsNull = length < 0;
+    binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+    if (status != STATUS_OK) return status;
+    if (length <= 0) return STATUS_OK;
+
+    for (int32_t i = 0; i < length; i++) {
+        binder_status_t status = elementWriter(parcel, arrayData, i);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
+                                            AParcel_parcelableArrayAllocator allocator,
+                                            AParcel_readParcelableElement elementReader) {
+    const Parcel* rawParcel = parcel->get();
+
+    int32_t length;
+    status_t status = rawParcel->readInt32(&length);
+
+    if (status != STATUS_OK) return PruneStatusT(status);
+    if (length < -1) return STATUS_BAD_VALUE;
+
+    if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+
+    if (length == -1) return STATUS_OK;  // null array
+
+    for (int32_t i = 0; i < length; i++) {
+        binder_status_t status = elementReader(parcel, arrayData, i);
+        if (status != STATUS_OK) return status;
+    }
+
+    return STATUS_OK;
+}
+
+// See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
+// libbinder and this library.
+// @START
+binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) {
+    status_t status = parcel->get()->writeInt32(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) {
+    status_t status = parcel->get()->writeUint32(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) {
+    status_t status = parcel->get()->writeInt64(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) {
+    status_t status = parcel->get()->writeUint64(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeFloat(AParcel* parcel, float value) {
+    status_t status = parcel->get()->writeFloat(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeDouble(AParcel* parcel, double value) {
+    status_t status = parcel->get()->writeDouble(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeBool(AParcel* parcel, bool value) {
+    status_t status = parcel->get()->writeBool(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) {
+    status_t status = parcel->get()->writeChar(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) {
+    status_t status = parcel->get()->writeByte(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) {
+    status_t status = parcel->get()->readInt32(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) {
+    status_t status = parcel->get()->readUint32(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) {
+    status_t status = parcel->get()->readInt64(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) {
+    status_t status = parcel->get()->readUint64(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) {
+    status_t status = parcel->get()->readFloat(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) {
+    status_t status = parcel->get()->readDouble(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) {
+    status_t status = parcel->get()->readBool(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) {
+    status_t status = parcel->get()->readChar(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) {
+    status_t status = parcel->get()->readByte(value);
+    return PruneStatusT(status);
+}
+
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) {
+    return WriteArray<int32_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData,
+                                         int32_t length) {
+    return WriteArray<uint32_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) {
+    return WriteArray<int64_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData,
+                                         int32_t length) {
+    return WriteArray<uint64_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) {
+    return WriteArray<float>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) {
+    return WriteArray<double>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length,
+                                       AParcel_boolArrayGetter getter) {
+    return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool);
+}
+
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) {
+    return WriteArray<char16_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) {
+    return WriteArray<int8_t>(parcel, arrayData, length);
+}
+
+binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int32ArrayAllocator allocator) {
+    return ReadArray<int32_t>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint32ArrayAllocator allocator) {
+    return ReadArray<uint32_t>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
+                                       AParcel_int64ArrayAllocator allocator) {
+    return ReadArray<int64_t>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
+                                        AParcel_uint64ArrayAllocator allocator) {
+    return ReadArray<uint64_t>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
+                                       AParcel_floatArrayAllocator allocator) {
+    return ReadArray<float>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
+                                        AParcel_doubleArrayAllocator allocator) {
+    return ReadArray<double>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_boolArrayAllocator allocator,
+                                      AParcel_boolArraySetter setter) {
+    return ReadArray<bool>(parcel, arrayData, allocator, setter, &Parcel::readBool);
+}
+
+binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_charArrayAllocator allocator) {
+    return ReadArray<char16_t>(parcel, arrayData, allocator);
+}
+
+binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
+                                      AParcel_byteArrayAllocator allocator) {
+    return ReadArray<int8_t>(parcel, arrayData, allocator);
+}
+
+// @END
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
new file mode 100644
index 0000000..6b7295e
--- /dev/null
+++ b/libs/binder/ndk/parcel_internal.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+#include <sys/cdefs.h>
+
+#include <binder/Parcel.h>
+#include "ibinder_internal.h"
+
+struct AParcel {
+    const ::android::Parcel* get() const { return mParcel; }
+    ::android::Parcel* get() { return mParcel; }
+
+    explicit AParcel(const AIBinder* binder)
+        : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
+    AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
+        : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+
+    ~AParcel() {
+        if (mOwns) {
+            delete mParcel;
+        }
+    }
+
+    static const AParcel readOnly(const AIBinder* binder, const ::android::Parcel* parcel) {
+        return AParcel(binder, const_cast<::android::Parcel*>(parcel), false);
+    }
+
+    const AIBinder* getBinder() { return mBinder; }
+
+   private:
+    // This object is associated with a calls to a specific AIBinder object. This is used for sanity
+    // checking to make sure that a parcel is one that is expected.
+    const AIBinder* mBinder;
+
+    ::android::Parcel* mParcel;
+    bool mOwns;
+};
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
new file mode 100644
index 0000000..c89caaf
--- /dev/null
+++ b/libs/binder/ndk/process.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_process.h>
+
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+
+using ::android::IPCThreadState;
+using ::android::ProcessState;
+
+void ABinderProcess_startThreadPool() {
+    ProcessState::self()->startThreadPool();
+    ProcessState::self()->giveThreadPoolName();
+}
+bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
+    return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
+}
+void ABinderProcess_joinThreadPool() {
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
new file mode 100755
index 0000000..a0c49fb
--- /dev/null
+++ b/libs/binder/ndk/runtests.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+set -ex
+
+function run_libbinder_ndk_test() {
+    adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+
+    # avoid getService 1s delay for most runs, non-critical
+    sleep 0.1
+
+    adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
+        adb shell killall libbinder_ndk_test_server
+}
+
+[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
+    MODULES-IN-frameworks-native-libs-binder-ndk
+
+adb root
+adb wait-for-device
+adb sync data
+
+# very simple unit tests, tests things outside of the NDK as well
+run_libbinder_ndk_test
+
+# CTS tests (much more comprehensive, new tests should ideally go here)
+atest android.binder.cts
diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh
new file mode 100755
index 0000000..698d291
--- /dev/null
+++ b/libs/binder/ndk/scripts/format.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+echo "Formatting code"
+
+bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp")
+clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\))
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
new file mode 100755
index 0000000..8f587d2
--- /dev/null
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+# list (pretty, cpp)
+data_types = [
+    ("Int32", "int32_t"),
+    ("Uint32", "uint32_t"),
+    ("Int64", "int64_t"),
+    ("Uint64", "uint64_t"),
+    ("Float", "float"),
+    ("Double", "double"),
+    ("Bool", "bool"),
+    ("Char", "char16_t"),
+    ("Byte", "int8_t"),
+]
+
+non_contiguously_addressable = {"Bool"}
+
+def replaceFileTags(path, content, start_tag, end_tag):
+    print("Updating", path)
+    with open(path, "r+") as f:
+        lines = f.readlines()
+
+        start = lines.index("// @" + start_tag + "\n")
+        end = lines.index("// @" + end_tag + "\n")
+
+        if end <= start or start < 0 or end < 0:
+            print("Failed to find tags in", path)
+            exit(1)
+
+        f.seek(0)
+        f.write("".join(lines[:start+1]) + content + "".join(lines[end:]))
+        f.truncate()
+
+def main():
+    if len(sys.argv) != 1:
+        print("No arguments.")
+        exit(1)
+
+    ABT = os.environ.get('ANDROID_BUILD_TOP', None)
+    if ABT is None:
+        print("Can't get ANDROID_BUILD_TOP. Lunch?")
+        exit(1)
+    ROOT = ABT + "/frameworks/native/libs/binder/ndk/"
+
+    print("Updating auto-generated code")
+
+    pre_header = ""
+    header = ""
+    source = ""
+    cpp_helper = ""
+
+    for pretty, cpp in data_types:
+        header += "/**\n"
+        header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to write to.\n"
+        header += " * \\param value the value to write to the parcel.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful write.\n"
+        header += " */\n"
+        header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n"
+        source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
+        source += "    status_t status = parcel->get()->write" + pretty + "(value);\n"
+        source += "    return PruneStatusT(status);\n"
+        source += "}\n\n"
+
+    for pretty, cpp in data_types:
+        header += "/**\n"
+        header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to read from.\n"
+        header += " * \\param value the value to read from the parcel.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful read.\n"
+        header += " */\n"
+        header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n"
+        source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
+        source += "    status_t status = parcel->get()->read" + pretty + "(value);\n"
+        source += "    return PruneStatusT(status);\n"
+        source += "}\n\n"
+
+    for pretty, cpp in data_types:
+        nca = pretty in non_contiguously_addressable
+
+        arg_types = "const " + cpp + "* arrayData, int32_t length"
+        if nca: arg_types = "const void* arrayData, int32_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
+        args = "arrayData, length"
+        if nca: args = "arrayData, length, getter, &Parcel::write" + pretty
+
+        header += "/**\n"
+        header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n"
+        if nca:
+            header += " *\n"
+            header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write "
+            header += "to the parcel.\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to write to.\n"
+        if nca:
+            header += " * \\param arrayData some external representation of an array.\n"
+            header += " * \\param length the length of arrayData (or -1 if this represents a null array).\n"
+            header += " * \\param getter the callback to retrieve data at specific locations in the array.\n"
+        else:
+            header += " * \\param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).\n"
+            header += " * \\param length the length of arrayData or -1 if this represents a null array.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful write.\n"
+        header += " */\n"
+        header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") __INTRODUCED_IN(29);\n\n"
+        source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") {\n"
+        source += "    return WriteArray<" + cpp + ">(parcel, " + args + ");\n";
+        source += "}\n\n"
+
+    for pretty, cpp in data_types:
+        nca = pretty in non_contiguously_addressable
+
+        read_func = "AParcel_read" + pretty + "Array"
+        write_func = "AParcel_write" + pretty + "Array"
+        allocator_type = "AParcel_" + pretty.lower() + "ArrayAllocator"
+        getter_type = "AParcel_" + pretty.lower() + "ArrayGetter"
+        setter_type = "AParcel_" + pretty.lower() + "ArraySetter"
+
+        if nca:
+            pre_header += "/**\n"
+            pre_header += " * This allocates an array of size 'length' inside of arrayData and returns whether or not there was "
+            pre_header += "a success. If length is -1, then this should allocate some representation of a null array.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param length the length to allocate arrayData to (or -1 if this represents a null array).\n"
+            pre_header += " *\n"
+            pre_header += " * \\return whether the allocation succeeded.\n"
+            pre_header += " */\n"
+            pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length);\n\n"
+
+            pre_header += "/**\n"
+            pre_header += " * This is called to get the underlying data from an arrayData object at index.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + write_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param index the index of the value to be retrieved.\n"
+            pre_header += " *\n"
+            pre_header += " * \\return the value of the array at index index.\n"
+            pre_header += " */\n"
+            pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n"
+
+            pre_header += "/**\n"
+            pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param index the index of the value to be set.\n"
+            pre_header += " * \\param value the value to set at index index.\n"
+            pre_header += " */\n"
+            pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
+        else:
+            pre_header += "/**\n"
+            pre_header += " * This is called to get the underlying data from an arrayData object.\n"
+            pre_header += " *\n"
+            pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and "
+            pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be "
+            pre_header += "returned. If length is -1, this should allocate some representation of a null array.\n"
+            pre_header += " *\n"
+            pre_header += " * See also " + read_func + "\n"
+            pre_header += " *\n"
+            pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+            pre_header += " * \\param length the length to allocate arrayData to.\n"
+            pre_header += " * \\param outBuffer a buffer of " + cpp + " of size 'length' (if length is >= 0, if length is 0, "
+            pre_header += "this may be nullptr).\n"
+            pre_header += " *\n"
+            pre_header += " * \\return whether or not the allocation was successful (or whether a null array is represented when length is -1).\n"
+            pre_header += " */\n"
+            pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length, " + cpp + "** outBuffer);\n\n"
+
+        read_array_args = [("const AParcel*", "parcel")]
+        read_array_args += [("void*", "arrayData")]
+        read_array_args += [(allocator_type, "allocator")]
+        if nca: read_array_args += [(setter_type, "setter")]
+
+        read_type_args = ", ".join((varType + " " + name for varType, name in read_array_args))
+        read_call_args = ", ".join((name for varType, name in read_array_args))
+
+        header += "/**\n"
+        header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n"
+        header += " *\n"
+        if nca:
+            header += " * First, allocator will be called with the length of the array. Then, for every i in [0, length), "
+            header += "setter(arrayData, i, x) will be called where x is the value at the associated index.\n"
+        else:
+            header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the "
+            header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n"
+        header += " *\n"
+        header += " * \\param parcel the parcel to read from.\n"
+        header += " * \\param arrayData some external representation of an array.\n"
+        header += " * \\param allocator the callback that will be called to allocate the array.\n"
+        if nca:
+            header += " * \\param setter the callback that will be called to set a value at a specific location in the array.\n"
+        header += " *\n"
+        header += " * \\return STATUS_OK on successful read.\n"
+        header += " */\n"
+        header += "binder_status_t " + read_func + "(" + read_type_args + ") __INTRODUCED_IN(29);\n\n"
+        source += "binder_status_t " + read_func + "(" + read_type_args + ") {\n"
+        additional_args = ""
+        if nca: additional_args = ", &Parcel::read" + pretty
+        source += "    return ReadArray<" + cpp + ">(" + read_call_args + additional_args + ");\n";
+        source += "}\n\n"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n"
+        cpp_helper += " */\n"
+        cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n"
+        write_args = "vec.data(), vec.size()"
+        if nca: write_args = "static_cast<const void*>(&vec), vec.size(), AParcel_stdVectorGetter<" + cpp + ">"
+        cpp_helper += "    return AParcel_write" + pretty + "Array(parcel, " + write_args + ");\n"
+        cpp_helper += "}\n\n"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Writes an optional vector of " + cpp + " to the next location in a non-null parcel.\n"
+        cpp_helper += " */\n"
+        cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::optional<std::vector<" + cpp + ">>& vec) {\n"
+        extra_args = ""
+        if nca: extra_args = ", AParcel_stdVectorGetter<" + cpp + ">"
+        cpp_helper += "    if (!vec) return AParcel_write" + pretty + "Array(parcel, nullptr, -1" + extra_args + ");\n"
+        cpp_helper += "    return AParcel_writeVector(parcel, *vec);\n"
+        cpp_helper += "}\n\n"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
+        cpp_helper += " */\n"
+        cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
+        cpp_helper += "    void* vectorData = static_cast<void*>(vec);\n"
+        read_args = []
+        read_args += ["parcel"]
+        read_args += ["vectorData"]
+        if nca:
+            read_args += ["AParcel_stdVectorExternalAllocator<bool>"]
+            read_args += ["AParcel_stdVectorSetter<" + cpp + ">"]
+        else:
+            read_args += ["AParcel_stdVectorAllocator<" + cpp + ">"]
+        cpp_helper += "    return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
+        cpp_helper += "}\n\n"
+
+        cpp_helper += "/**\n"
+        cpp_helper += " * Reads an optional vector of " + cpp + " from the next location in a non-null parcel.\n"
+        cpp_helper += " */\n"
+        cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::optional<std::vector<" + cpp + ">>* vec) {\n"
+        cpp_helper += "    void* vectorData = static_cast<void*>(vec);\n"
+        read_args = []
+        read_args += ["parcel"]
+        read_args += ["vectorData"]
+        if nca:
+            read_args += ["AParcel_nullableStdVectorExternalAllocator<bool>"]
+            read_args += ["AParcel_nullableStdVectorSetter<" + cpp + ">"]
+        else:
+            read_args += ["AParcel_nullableStdVectorAllocator<" + cpp + ">"]
+        cpp_helper += "    return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
+        cpp_helper += "}\n\n"
+
+    replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", pre_header, "START-PRIMITIVE-VECTOR-GETTERS", "END-PRIMITIVE-VECTOR-GETTERS")
+    replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header, "START-PRIMITIVE-READ-WRITE", "END-PRIMITIVE-READ-WRITE")
+    replaceFileTags(ROOT + "parcel.cpp", source, "START", "END")
+    replaceFileTags(ROOT + "include_ndk/android/binder_parcel_utils.h", cpp_helper, "START", "END")
+
+    print("Updating DONE.")
+
+if __name__ == "__main__":
+    main()
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
new file mode 100755
index 0000000..3529b72
--- /dev/null
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# Simple helper for ease of development until this API is frozen.
+
+echo "LIBBINDER_NDK { # introduced=29"
+echo "  global:"
+{
+    grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder.h;
+    grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder_jni.h;
+    grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
+    grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
+} | sort | uniq | awk '{ print "    " $0 ";"; }'
+{
+    grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
+    grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
+} | sort | uniq | awk '{ print "    " $0 "; # apex"; }'
+echo "  local:"
+echo "    *;"
+echo "};"
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
new file mode 100644
index 0000000..d0b166d
--- /dev/null
+++ b/libs/binder/ndk/service_manager.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_manager.h>
+
+#include "ibinder_internal.h"
+#include "status_internal.h"
+
+#include <binder/IServiceManager.h>
+
+using ::android::defaultServiceManager;
+using ::android::IBinder;
+using ::android::IServiceManager;
+using ::android::sp;
+using ::android::status_t;
+using ::android::String16;
+
+binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance) {
+    if (binder == nullptr || instance == nullptr) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    status_t status = sm->addService(String16(instance), binder->getBinder());
+    return PruneStatusT(status);
+}
+AIBinder* AServiceManager_checkService(const char* instance) {
+    if (instance == nullptr) {
+        return nullptr;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->checkService(String16(instance));
+
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+    AIBinder_incStrong(ret.get());
+    return ret.get();
+}
+AIBinder* AServiceManager_getService(const char* instance) {
+    if (instance == nullptr) {
+        return nullptr;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16(instance));
+
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+    AIBinder_incStrong(ret.get());
+    return ret.get();
+}
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
new file mode 100644
index 0000000..1f75b0b
--- /dev/null
+++ b/libs/binder/ndk/status.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_status.h>
+#include "status_internal.h"
+
+#include <android-base/logging.h>
+
+using ::android::status_t;
+using ::android::binder::Status;
+
+AStatus* AStatus_newOk() {
+    return new AStatus();
+}
+
+AStatus* AStatus_fromExceptionCode(binder_exception_t exception) {
+    return new AStatus(Status::fromExceptionCode(PruneException(exception)));
+}
+
+AStatus* AStatus_fromExceptionCodeWithMessage(binder_exception_t exception, const char* message) {
+    return new AStatus(Status::fromExceptionCode(PruneException(exception), message));
+}
+
+AStatus* AStatus_fromServiceSpecificError(int32_t serviceSpecific) {
+    return new AStatus(Status::fromServiceSpecificError(serviceSpecific));
+}
+
+AStatus* AStatus_fromServiceSpecificErrorWithMessage(int32_t serviceSpecific, const char* message) {
+    return new AStatus(Status::fromServiceSpecificError(serviceSpecific, message));
+}
+
+AStatus* AStatus_fromStatus(binder_status_t status) {
+    return new AStatus(Status::fromStatusT(PruneStatusT(status)));
+}
+
+bool AStatus_isOk(const AStatus* status) {
+    return status->get()->isOk();
+}
+
+binder_exception_t AStatus_getExceptionCode(const AStatus* status) {
+    return PruneException(status->get()->exceptionCode());
+}
+
+int32_t AStatus_getServiceSpecificError(const AStatus* status) {
+    return status->get()->serviceSpecificErrorCode();
+}
+
+binder_status_t AStatus_getStatus(const AStatus* status) {
+    return PruneStatusT(status->get()->transactionError());
+}
+
+const char* AStatus_getMessage(const AStatus* status) {
+    return status->get()->exceptionMessage().c_str();
+}
+
+void AStatus_delete(AStatus* status) {
+    delete status;
+}
+
+binder_status_t PruneStatusT(status_t status) {
+    switch (status) {
+        case ::android::OK:
+            return STATUS_OK;
+        case ::android::NO_MEMORY:
+            return STATUS_NO_MEMORY;
+        case ::android::INVALID_OPERATION:
+            return STATUS_INVALID_OPERATION;
+        case ::android::BAD_VALUE:
+            return STATUS_BAD_VALUE;
+        case ::android::BAD_TYPE:
+            return STATUS_BAD_TYPE;
+        case ::android::NAME_NOT_FOUND:
+            return STATUS_NAME_NOT_FOUND;
+        case ::android::PERMISSION_DENIED:
+            return STATUS_PERMISSION_DENIED;
+        case ::android::NO_INIT:
+            return STATUS_NO_INIT;
+        case ::android::ALREADY_EXISTS:
+            return STATUS_ALREADY_EXISTS;
+        case ::android::DEAD_OBJECT:
+            return STATUS_DEAD_OBJECT;
+        case ::android::FAILED_TRANSACTION:
+            return STATUS_FAILED_TRANSACTION;
+        case ::android::BAD_INDEX:
+            return STATUS_BAD_INDEX;
+        case ::android::NOT_ENOUGH_DATA:
+            return STATUS_NOT_ENOUGH_DATA;
+        case ::android::WOULD_BLOCK:
+            return STATUS_WOULD_BLOCK;
+        case ::android::TIMED_OUT:
+            return STATUS_TIMED_OUT;
+        case ::android::UNKNOWN_TRANSACTION:
+            return STATUS_UNKNOWN_TRANSACTION;
+        case ::android::FDS_NOT_ALLOWED:
+            return STATUS_FDS_NOT_ALLOWED;
+        case ::android::UNEXPECTED_NULL:
+            return STATUS_UNEXPECTED_NULL;
+        case ::android::UNKNOWN_ERROR:
+            return STATUS_UNKNOWN_ERROR;
+
+        default:
+            LOG(WARNING) << __func__
+                         << ": Unknown status_t pruned into STATUS_UNKNOWN_ERROR: " << status;
+            return STATUS_UNKNOWN_ERROR;
+    }
+}
+
+binder_exception_t PruneException(int32_t exception) {
+    switch (exception) {
+        case Status::EX_NONE:
+            return EX_NONE;
+        case Status::EX_SECURITY:
+            return EX_SECURITY;
+        case Status::EX_BAD_PARCELABLE:
+            return EX_BAD_PARCELABLE;
+        case Status::EX_ILLEGAL_ARGUMENT:
+            return EX_ILLEGAL_ARGUMENT;
+        case Status::EX_NULL_POINTER:
+            return EX_NULL_POINTER;
+        case Status::EX_ILLEGAL_STATE:
+            return EX_ILLEGAL_STATE;
+        case Status::EX_NETWORK_MAIN_THREAD:
+            return EX_NETWORK_MAIN_THREAD;
+        case Status::EX_UNSUPPORTED_OPERATION:
+            return EX_UNSUPPORTED_OPERATION;
+        case Status::EX_SERVICE_SPECIFIC:
+            return EX_SERVICE_SPECIFIC;
+        case Status::EX_PARCELABLE:
+            return EX_PARCELABLE;
+        case Status::EX_TRANSACTION_FAILED:
+            return EX_TRANSACTION_FAILED;
+
+        default:
+            LOG(WARNING) << __func__
+                         << ": Unknown status_t pruned into EX_TRANSACTION_FAILED: " << exception;
+            return EX_TRANSACTION_FAILED;
+    }
+}
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
new file mode 100644
index 0000000..f6227f7
--- /dev/null
+++ b/libs/binder/ndk/status_internal.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_status.h>
+
+#include <binder/Status.h>
+#include <utils/Errors.h>
+
+struct AStatus {
+    AStatus() {}  // ok
+    explicit AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
+
+    ::android::binder::Status* get() { return &mStatus; }
+    const ::android::binder::Status* get() const { return &mStatus; }
+
+   private:
+    ::android::binder::Status mStatus;
+};
+
+// This collapses the statuses into the declared range.
+binder_status_t PruneStatusT(android::status_t status);
+
+// This collapses the exception into the declared range.
+binder_exception_t PruneException(int32_t exception);
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
new file mode 100644
index 0000000..8cd4e03
--- /dev/null
+++ b/libs/binder/ndk/test/Android.bp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_defaults {
+    name: "test_libbinder_ndk_defaults",
+    shared_libs: [
+        "libbase",
+    ],
+    strip: {
+        none: true,
+    },
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
+
+cc_library_static {
+    name: "test_libbinder_ndk_library",
+    defaults: ["test_libbinder_ndk_defaults"],
+    export_include_dirs: ["include"],
+    shared_libs: ["libbinder_ndk"],
+    export_shared_lib_headers: ["libbinder_ndk"],
+    srcs: ["iface.cpp"],
+}
+
+cc_defaults {
+    name: "test_libbinder_ndk_test_defaults",
+    defaults: ["test_libbinder_ndk_defaults"],
+    shared_libs: [
+        "libandroid_runtime_lazy",
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+    static_libs: [
+        "libbinder_ndk",
+        "test_libbinder_ndk_library",
+    ],
+}
+
+// This test is a unit test of the low-level API that is presented here,
+// specifically the parts which are outside of the NDK. Actual users should
+// also instead use AIDL to generate these stubs. See android.binder.cts.
+cc_test {
+    name: "libbinder_ndk_test_client",
+    defaults: ["test_libbinder_ndk_test_defaults"],
+    srcs: ["main_client.cpp"],
+}
+
+cc_test {
+    name: "libbinder_ndk_test_server",
+    defaults: ["test_libbinder_ndk_test_defaults"],
+    srcs: ["main_server.cpp"],
+    gtest: false,
+}
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
new file mode 100644
index 0000000..64832f3
--- /dev/null
+++ b/libs/binder/ndk/test/iface.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <iface/iface.h>
+
+#include <android/binder_auto_utils.h>
+
+using ::android::sp;
+using ::android::wp;
+
+const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
+const char* kIFooDescriptor = "my-special-IFoo-class";
+
+struct IFoo_Class_Data {
+    sp<IFoo> foo;
+};
+
+void* IFoo_Class_onCreate(void* args) {
+    IFoo_Class_Data* foo = static_cast<IFoo_Class_Data*>(args);
+    // This is a foo, but we're currently not verifying that. So, the method newLocalBinder is
+    // coupled with this.
+    return static_cast<void*>(foo);
+}
+
+void IFoo_Class_onDestroy(void* userData) {
+    delete static_cast<IFoo_Class_Data*>(userData);
+}
+
+binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, const AParcel* in,
+                                      AParcel* out) {
+    binder_status_t stat = STATUS_FAILED_TRANSACTION;
+
+    sp<IFoo> foo = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder))->foo;
+    CHECK(foo != nullptr) << "Transaction made on already deleted object";
+
+    switch (code) {
+        case IFoo::DOFOO: {
+            int32_t valueIn;
+            int32_t valueOut;
+            stat = AParcel_readInt32(in, &valueIn);
+            if (stat != STATUS_OK) break;
+            stat = foo->doubleNumber(valueIn, &valueOut);
+            if (stat != STATUS_OK) break;
+            stat = AParcel_writeInt32(out, valueOut);
+            break;
+        }
+        case IFoo::DIE: {
+            stat = foo->die();
+            break;
+        }
+    }
+
+    return stat;
+}
+
+AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate,
+                                                     IFoo_Class_onDestroy, IFoo_Class_onTransact);
+
+class BpFoo : public IFoo {
+   public:
+    explicit BpFoo(AIBinder* binder) : mBinder(binder) {}
+    virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
+
+    virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
+        binder_status_t stat = STATUS_OK;
+
+        AParcel* parcelIn;
+        stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+        if (stat != STATUS_OK) return stat;
+
+        stat = AParcel_writeInt32(parcelIn, in);
+        if (stat != STATUS_OK) return stat;
+
+        ::ndk::ScopedAParcel parcelOut;
+        stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+        if (stat != STATUS_OK) return stat;
+
+        stat = AParcel_readInt32(parcelOut.get(), out);
+        if (stat != STATUS_OK) return stat;
+
+        return stat;
+    }
+
+    virtual binder_status_t die() {
+        binder_status_t stat = STATUS_OK;
+
+        AParcel* parcelIn;
+        stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+
+        ::ndk::ScopedAParcel parcelOut;
+        stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+
+        return stat;
+    }
+
+   private:
+    // Always assumes one refcount
+    AIBinder* mBinder;
+};
+
+IFoo::~IFoo() {
+    AIBinder_Weak_delete(mWeakBinder);
+}
+
+binder_status_t IFoo::addService(const char* instance) {
+    AIBinder* binder = nullptr;
+
+    if (mWeakBinder != nullptr) {
+        // one strong ref count of binder
+        binder = AIBinder_Weak_promote(mWeakBinder);
+    }
+    if (binder == nullptr) {
+        // or one strong refcount here
+        binder = AIBinder_new(IFoo::kClass, static_cast<void*>(new IFoo_Class_Data{this}));
+        if (mWeakBinder != nullptr) {
+            AIBinder_Weak_delete(mWeakBinder);
+        }
+        mWeakBinder = AIBinder_Weak_new(binder);
+    }
+
+    binder_status_t status = AServiceManager_addService(binder, instance);
+    // Strong references we care about kept by remote process
+    AIBinder_decStrong(binder);
+    return status;
+}
+
+sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) {
+    AIBinder* binder = AServiceManager_getService(instance);  // maybe nullptr
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    if (!AIBinder_associateClass(binder, IFoo::kClass)) {
+        AIBinder_decStrong(binder);
+        return nullptr;
+    }
+
+    if (outBinder != nullptr) {
+        AIBinder_incStrong(binder);
+        *outBinder = binder;
+    }
+
+    if (AIBinder_isRemote(binder)) {
+        sp<IFoo> ret = new BpFoo(binder);  // takes ownership of binder
+        return ret;
+    }
+
+    IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
+
+    CHECK(data != nullptr);  // always created with non-null data
+
+    sp<IFoo> ret = data->foo;
+
+    AIBinder* held = AIBinder_Weak_promote(ret->mWeakBinder);
+    CHECK(held == binder);
+    AIBinder_decStrong(held);
+
+    AIBinder_decStrong(binder);
+    return ret;
+}
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
new file mode 100644
index 0000000..cdf5493
--- /dev/null
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <utils/RefBase.h>
+
+// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of
+// the other niceties make sure that, for instance, binder proxies are always the same. They also
+// don't use internal Android APIs like refbase which are used here only for convenience.
+
+class IFoo : public virtual ::android::RefBase {
+   public:
+    static const char* kSomeInstanceName;
+    static const char* kInstanceNameToDieFor;
+
+    static AIBinder_Class* kClass;
+
+    // Takes ownership of IFoo
+    binder_status_t addService(const char* instance);
+    static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
+
+    enum Call {
+        DOFOO = FIRST_CALL_TRANSACTION + 0,
+        DIE = FIRST_CALL_TRANSACTION + 1,
+    };
+
+    virtual ~IFoo();
+
+    virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
+    virtual binder_status_t die() = 0;
+
+   private:
+    // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
+    // for BpFoo.
+    AIBinder_Weak* mWeakBinder = nullptr;
+};
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
new file mode 100644
index 0000000..8467734
--- /dev/null
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_ibinder_jni.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <iface/iface.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+using ::android::sp;
+
+constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
+
+// This is too slow
+// TEST(NdkBinder, GetServiceThatDoesntExist) {
+//     sp<IFoo> foo = IFoo::getService("asdfghkl;");
+//     EXPECT_EQ(nullptr, foo.get());
+// }
+
+TEST(NdkBinder, CheckServiceThatDoesntExist) {
+    AIBinder* binder = AServiceManager_checkService("asdfghkl;");
+    ASSERT_EQ(nullptr, binder);
+}
+
+TEST(NdkBinder, CheckServiceThatDoesExist) {
+    AIBinder* binder = AServiceManager_checkService(kExistingNonNdkService);
+    EXPECT_NE(nullptr, binder);
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder));
+
+    AIBinder_decStrong(binder);
+}
+
+TEST(NdkBinder, DoubleNumber) {
+    sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
+    ASSERT_NE(foo, nullptr);
+
+    int32_t out;
+    EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out));
+    EXPECT_EQ(2, out);
+}
+
+void LambdaOnDeath(void* cookie) {
+    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
+    (*onDeath)();
+};
+TEST(NdkBinder, DeathRecipient) {
+    using namespace std::chrono_literals;
+
+    AIBinder* binder;
+    sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder);
+    ASSERT_NE(nullptr, foo.get());
+    ASSERT_NE(nullptr, binder);
+
+    std::mutex deathMutex;
+    std::condition_variable deathCv;
+    bool deathRecieved = false;
+
+    std::function<void(void)> onDeath = [&] {
+        std::cerr << "Binder died (as requested)." << std::endl;
+        deathRecieved = true;
+        deathCv.notify_one();
+    };
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+
+    // the binder driver should return this if the service dies during the transaction
+    EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+    foo = nullptr;
+    AIBinder_decStrong(binder);
+    binder = nullptr;
+
+    std::unique_lock<std::mutex> lock(deathMutex);
+    EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
+    EXPECT_TRUE(deathRecieved);
+
+    AIBinder_DeathRecipient_delete(recipient);
+}
+
+TEST(NdkBinder, RetrieveNonNdkService) {
+    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binder);
+    EXPECT_TRUE(AIBinder_isRemote(binder));
+    EXPECT_TRUE(AIBinder_isAlive(binder));
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder));
+
+    AIBinder_decStrong(binder);
+}
+
+void OnBinderDeath(void* cookie) {
+    LOG(ERROR) << "BINDER DIED. COOKIE: " << cookie;
+}
+
+TEST(NdkBinder, LinkToDeath) {
+    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binder);
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(OnBinderDeath);
+    ASSERT_NE(nullptr, recipient);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, nullptr));
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, nullptr));
+    EXPECT_EQ(STATUS_OK, AIBinder_unlinkToDeath(binder, recipient, nullptr));
+    EXPECT_EQ(STATUS_OK, AIBinder_unlinkToDeath(binder, recipient, nullptr));
+    EXPECT_EQ(STATUS_NAME_NOT_FOUND, AIBinder_unlinkToDeath(binder, recipient, nullptr));
+
+    AIBinder_DeathRecipient_delete(recipient);
+    AIBinder_decStrong(binder);
+}
+
+class MyTestFoo : public IFoo {
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+    binder_status_t die() override {
+        ADD_FAILURE() << "die called on local instance";
+        return STATUS_OK;
+    }
+};
+
+TEST(NdkBinder, GetServiceInProcess) {
+    static const char* kInstanceName = "test-get-service-in-process";
+
+    sp<IFoo> foo = new MyTestFoo;
+    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName));
+
+    sp<IFoo> getFoo = IFoo::getService(kInstanceName);
+    EXPECT_EQ(foo.get(), getFoo.get());
+
+    int32_t out;
+    EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
+    EXPECT_EQ(2, out);
+}
+
+TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
+    AIBinder* binderA = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binderA);
+
+    AIBinder* binderB = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binderB);
+
+    EXPECT_EQ(binderA, binderB);
+
+    AIBinder_decStrong(binderA);
+    AIBinder_decStrong(binderB);
+}
+
+TEST(NdkBinder, ToFromJavaNullptr) {
+    EXPECT_EQ(nullptr, AIBinder_toJavaBinder(nullptr, nullptr));
+    EXPECT_EQ(nullptr, AIBinder_fromJavaBinder(nullptr, nullptr));
+}
+
+TEST(NdkBinder, ABpBinderRefCount) {
+    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+    AIBinder_Weak* wBinder = AIBinder_Weak_new(binder);
+
+    ASSERT_NE(nullptr, binder);
+    EXPECT_EQ(1, AIBinder_debugGetRefCount(binder));
+
+    AIBinder_decStrong(binder);
+
+    // assert because would need to decStrong if non-null and we shouldn't need to add a no-op here
+    ASSERT_NE(nullptr, AIBinder_Weak_promote(wBinder));
+
+    AIBinder_Weak_delete(wBinder);
+}
+
+TEST(NdkBinder, AddServiceMultipleTimes) {
+    static const char* kInstanceName1 = "test-multi-1";
+    static const char* kInstanceName2 = "test-multi-2";
+    sp<IFoo> foo = new MyTestFoo;
+    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName1));
+    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName2));
+    EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
+}
+
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
+    ABinderProcess_startThreadPool();
+
+    return RUN_ALL_TESTS();
+}
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
new file mode 100644
index 0000000..a6e17e8
--- /dev/null
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_process.h>
+#include <iface/iface.h>
+
+using ::android::sp;
+
+class MyFoo : public IFoo {
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+
+    binder_status_t die() override {
+        LOG(FATAL) << "IFoo::die called!";
+        return STATUS_UNKNOWN_ERROR;
+    }
+};
+
+int service(const char* instance) {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // Strong reference to MyFoo kept by service manager.
+    binder_status_t status = (new MyFoo)->addService(instance);
+
+    if (status != STATUS_OK) {
+        LOG(FATAL) << "Could not register: " << status << " " << instance;
+    }
+
+    ABinderProcess_joinThreadPool();
+
+    return 1;  // should not return
+}
+
+int main() {
+    if (fork() == 0) {
+        return service(IFoo::kInstanceNameToDieFor);
+    }
+
+    return service(IFoo::kSomeInstanceName);
+}
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
new file mode 100755
index 0000000..9a4577f
--- /dev/null
+++ b/libs/binder/ndk/update.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+set -ex
+
+# This script makes sure that the source code is in sync with the various scripts
+./scripts/gen_parcel_helper.py
+./scripts/format.sh
+./scripts/init_map.sh > libbinder_ndk.map.txt
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 4f00bc1..77ebac8 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -36,8 +36,8 @@
 
             m_binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC);
             ASSERT_GE(m_binderFd, 0);
-            m_buffer = mmap(NULL, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0);
-            ASSERT_NE(m_buffer, (void *)NULL);
+            m_buffer = mmap(nullptr, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0);
+            ASSERT_NE(m_buffer, (void *)nullptr);
             ret = ioctl(m_binderFd, BINDER_SET_MAX_THREADS, &max_threads);
             EXPECT_EQ(0, ret);
             EnterLooper();
@@ -156,23 +156,23 @@
 }
 
 TEST_F(BinderDriverInterfaceTest, WriteReadNull) {
-    binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT);
+    binderTestIoctlErr1(BINDER_WRITE_READ, nullptr, EFAULT);
 }
 
 TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNull) {
-    binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, NULL, EFAULT, EINVAL);
+    binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, nullptr, EFAULT, EINVAL);
 }
 
 TEST_F(BinderDriverInterfaceTest, SetMaxThreadsNull) {
-    binderTestIoctlErr2(BINDER_SET_MAX_THREADS, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
+    binderTestIoctlErr2(BINDER_SET_MAX_THREADS, nullptr, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
 }
 
 TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNull) {
-    binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, NULL, EFAULT, EINVAL);
+    binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, nullptr, EFAULT, EINVAL);
 }
 
 TEST_F(BinderDriverInterfaceTest, VersionNull) {
-    binderTestIoctlErr2(BINDER_VERSION, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
+    binderTestIoctlErr2(BINDER_VERSION, nullptr, EFAULT, EINVAL); /* TODO: don't accept EINVAL */
 }
 
 TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNoTest) {
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 1611e11..78f1159 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -65,11 +65,14 @@
     BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION,
     BINDER_LIB_TEST_LINK_DEATH_TRANSACTION,
     BINDER_LIB_TEST_WRITE_FILE_TRANSACTION,
+    BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION,
     BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION,
     BINDER_LIB_TEST_EXIT_TRANSACTION,
     BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
     BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
     BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
+    BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
+    BINDER_LIB_TEST_ECHO_VECTOR,
 };
 
 pid_t start_server_process(int arg2, bool usePoll = false)
@@ -88,7 +91,7 @@
         strpipefd1,
         usepoll,
         binderserversuffix,
-        NULL
+        nullptr
     };
 
     ret = pipe(pipefd);
@@ -123,7 +126,7 @@
         }
     }
     if (ret < 0) {
-        wait(NULL);
+        wait(nullptr);
         return ret;
     }
     return pid;
@@ -145,7 +148,7 @@
             sp<IServiceManager> sm = defaultServiceManager();
             //printf("%s: pid %d, get service\n", __func__, m_pid);
             m_server = sm->getService(binderLibTestServiceName);
-            ASSERT_TRUE(m_server != NULL);
+            ASSERT_TRUE(m_server != nullptr);
             //printf("%s: pid %d, get service done\n", __func__, m_pid);
         }
         virtual void TearDown() {
@@ -155,7 +158,7 @@
             pid_t pid;
 
             //printf("%s: pid %d\n", __func__, m_pid);
-            if (m_server != NULL) {
+            if (m_server != nullptr) {
                 ret = m_server->transact(BINDER_LIB_TEST_GET_STATUS_TRANSACTION, data, &reply);
                 EXPECT_EQ(0, ret);
                 ret = m_server->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY);
@@ -178,6 +181,7 @@
     public:
         virtual void SetUp() {
             m_server = static_cast<BinderLibTestEnv *>(binder_env)->getServer();
+            IPCThreadState::self()->restoreCallingWorkSource(0); 
         }
         virtual void TearDown() {
         }
@@ -192,9 +196,9 @@
             ret = m_server->transact(code, data, &reply);
             EXPECT_EQ(NO_ERROR, ret);
 
-            EXPECT_FALSE(binder != NULL);
+            EXPECT_FALSE(binder != nullptr);
             binder = reply.readStrongBinder();
-            EXPECT_TRUE(binder != NULL);
+            EXPECT_TRUE(binder != nullptr);
             ret = reply.readInt32(&id);
             EXPECT_EQ(NO_ERROR, ret);
             if (idPtr)
@@ -202,12 +206,12 @@
             return binder;
         }
 
-        sp<IBinder> addServer(int32_t *idPtr = NULL)
+        sp<IBinder> addServer(int32_t *idPtr = nullptr)
         {
             return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_SERVER);
         }
 
-        sp<IBinder> addPollServer(int32_t *idPtr = NULL)
+        sp<IBinder> addPollServer(int32_t *idPtr = nullptr)
         {
             return addServerEtc(idPtr, BINDER_LIB_TEST_ADD_POLL_SERVER);
         }
@@ -229,7 +233,7 @@
 {
     public:
         BinderLibTestBundle(void) {}
-        BinderLibTestBundle(const Parcel *source) : m_isValid(false) {
+        explicit BinderLibTestBundle(const Parcel *source) : m_isValid(false) {
             int32_t mark;
             int32_t bundleLen;
             size_t pos;
@@ -274,8 +278,8 @@
         BinderLibTestEvent(void)
             : m_eventTriggered(false)
         {
-            pthread_mutex_init(&m_waitMutex, NULL);
-            pthread_cond_init(&m_waitCond, NULL);
+            pthread_mutex_init(&m_waitMutex, nullptr);
+            pthread_cond_init(&m_waitCond, nullptr);
         }
         int waitEvent(int timeout_s)
         {
@@ -315,7 +319,7 @@
     public:
         BinderLibTestCallBack()
             : m_result(NOT_ENOUGH_DATA)
-            , m_prev_end(NULL)
+            , m_prev_end(nullptr)
         {
         }
         status_t getResult(void)
@@ -413,7 +417,7 @@
     int32_t ptrsize;
     Parcel data, reply;
     sp<IBinder> server = addServer();
-    ASSERT_TRUE(server != NULL);
+    ASSERT_TRUE(server != nullptr);
     ret = server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply);
     EXPECT_EQ(NO_ERROR, ret);
     ret = reply.readInt32(&ptrsize);
@@ -436,7 +440,7 @@
         BinderLibTestBundle datai;
 
         server = addServer(&serverId[i]);
-        ASSERT_TRUE(server != NULL);
+        ASSERT_TRUE(server != nullptr);
         data.writeStrongBinder(server);
         data.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION);
         datai.appendTo(&data);
@@ -480,7 +484,7 @@
         BinderLibTestBundle datai2;
 
         server = addServer(&serverId[i]);
-        ASSERT_TRUE(server != NULL);
+        ASSERT_TRUE(server != nullptr);
         data.writeStrongBinder(server);
         data.writeInt32(BINDER_LIB_TEST_INDIRECT_TRANSACTION);
 
@@ -546,7 +550,7 @@
 TEST_F(BinderLibTest, AddServer)
 {
     sp<IBinder> server = addServer();
-    ASSERT_TRUE(server != NULL);
+    ASSERT_TRUE(server != nullptr);
 }
 
 TEST_F(BinderLibTest, DeathNotificationNoRefs)
@@ -557,7 +561,7 @@
 
     {
         sp<IBinder> binder = addServer();
-        ASSERT_TRUE(binder != NULL);
+        ASSERT_TRUE(binder != nullptr);
         ret = binder->linkToDeath(testDeathRecipient);
         EXPECT_EQ(NO_ERROR, ret);
     }
@@ -579,7 +583,7 @@
 
     {
         sp<IBinder> binder = addServer();
-        ASSERT_TRUE(binder != NULL);
+        ASSERT_TRUE(binder != nullptr);
         ret = binder->linkToDeath(testDeathRecipient);
         EXPECT_EQ(NO_ERROR, ret);
         wbinder = binder;
@@ -602,7 +606,7 @@
 
     {
         sp<IBinder> binder = addServer();
-        ASSERT_TRUE(binder != NULL);
+        ASSERT_TRUE(binder != nullptr);
         ret = binder->linkToDeath(testDeathRecipient);
         EXPECT_EQ(NO_ERROR, ret);
         sbinder = binder;
@@ -629,13 +633,13 @@
     sp<IBinder> passiveclient[clientcount];
 
     target = addServer();
-    ASSERT_TRUE(target != NULL);
+    ASSERT_TRUE(target != nullptr);
     for (int i = 0; i < clientcount; i++) {
         {
             Parcel data, reply;
 
             linkedclient[i] = addServer();
-            ASSERT_TRUE(linkedclient[i] != NULL);
+            ASSERT_TRUE(linkedclient[i] != nullptr);
             callBack[i] = new BinderLibTestCallBack();
             data.writeStrongBinder(target);
             data.writeStrongBinder(callBack[i]);
@@ -646,7 +650,7 @@
             Parcel data, reply;
 
             passiveclient[i] = addServer();
-            ASSERT_TRUE(passiveclient[i] != NULL);
+            ASSERT_TRUE(passiveclient[i] != nullptr);
             data.writeStrongBinder(target);
             ret = passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply, TF_ONE_WAY);
             EXPECT_EQ(NO_ERROR, ret);
@@ -671,9 +675,9 @@
     status_t ret;
     sp<BinderLibTestCallBack> callback;
     sp<IBinder> target = addServer();
-    ASSERT_TRUE(target != NULL);
+    ASSERT_TRUE(target != nullptr);
     sp<IBinder> client = addServer();
-    ASSERT_TRUE(client != NULL);
+    ASSERT_TRUE(client != nullptr);
 
     sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
 
@@ -763,16 +767,51 @@
     close(pipefd[0]);
 }
 
+TEST_F(BinderLibTest, PassParcelFileDescriptor) {
+    const int datasize = 123;
+    std::vector<uint8_t> writebuf(datasize);
+    for (size_t i = 0; i < writebuf.size(); ++i) {
+        writebuf[i] = i;
+    }
+
+    android::base::unique_fd read_end, write_end;
+    {
+        int pipefd[2];
+        ASSERT_EQ(0, pipe2(pipefd, O_NONBLOCK));
+        read_end.reset(pipefd[0]);
+        write_end.reset(pipefd[1]);
+    }
+    {
+        Parcel data;
+        EXPECT_EQ(NO_ERROR, data.writeDupParcelFileDescriptor(write_end.get()));
+        write_end.reset();
+        EXPECT_EQ(NO_ERROR, data.writeInt32(datasize));
+        EXPECT_EQ(NO_ERROR, data.write(writebuf.data(), datasize));
+
+        Parcel reply;
+        EXPECT_EQ(NO_ERROR,
+                  m_server->transact(BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION, data,
+                                     &reply));
+    }
+    std::vector<uint8_t> readbuf(datasize);
+    EXPECT_EQ(datasize, read(read_end.get(), readbuf.data(), datasize));
+    EXPECT_EQ(writebuf, readbuf);
+
+    waitForReadData(read_end.get(), 5000); /* wait for other proccess to close pipe */
+
+    EXPECT_EQ(0, read(read_end.get(), readbuf.data(), datasize));
+}
+
 TEST_F(BinderLibTest, PromoteLocal) {
     sp<IBinder> strong = new BBinder();
     wp<IBinder> weak = strong;
     sp<IBinder> strong_from_weak = weak.promote();
-    EXPECT_TRUE(strong != NULL);
+    EXPECT_TRUE(strong != nullptr);
     EXPECT_EQ(strong, strong_from_weak);
-    strong = NULL;
-    strong_from_weak = NULL;
+    strong = nullptr;
+    strong_from_weak = nullptr;
     strong_from_weak = weak.promote();
-    EXPECT_TRUE(strong_from_weak == NULL);
+    EXPECT_TRUE(strong_from_weak == nullptr);
 }
 
 TEST_F(BinderLibTest, PromoteRemote) {
@@ -781,8 +820,8 @@
     sp<IBinder> strong = new BBinder();
     sp<IBinder> server = addServer();
 
-    ASSERT_TRUE(server != NULL);
-    ASSERT_TRUE(strong != NULL);
+    ASSERT_TRUE(server != nullptr);
+    ASSERT_TRUE(strong != nullptr);
 
     ret = data.writeWeakBinder(strong);
     EXPECT_EQ(NO_ERROR, ret);
@@ -799,7 +838,7 @@
     EXPECT_EQ(NO_ERROR, ret);
 
     const flat_binder_object *fb = reply.readObject(false);
-    ASSERT_TRUE(fb != NULL);
+    ASSERT_TRUE(fb != nullptr);
     EXPECT_EQ(BINDER_TYPE_HANDLE, fb->hdr.type);
     EXPECT_EQ(m_server, ProcessState::self()->getStrongProxyForHandle(fb->handle));
     EXPECT_EQ((binder_uintptr_t)0, fb->cookie);
@@ -810,7 +849,7 @@
     status_t ret;
 
     sp<IBinder> server = addServer();
-    ASSERT_TRUE(server != NULL);
+    ASSERT_TRUE(server != nullptr);
 
     __u32 freedHandle;
     wp<IBinder> keepFreedBinder;
@@ -881,12 +920,12 @@
     data2.writeStrongBinder(callBack2);
     data2.writeInt32(0); // delay in us
 
-    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, NULL, TF_ONE_WAY);
+    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, nullptr, TF_ONE_WAY);
     EXPECT_EQ(NO_ERROR, ret);
 
     // The delay ensures that this second transaction will end up on the async_todo list
     // (for a single-threaded server)
-    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, NULL, TF_ONE_WAY);
+    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, nullptr, TF_ONE_WAY);
     EXPECT_EQ(NO_ERROR, ret);
 
     // The server will ensure that the two transactions are handled in the expected order;
@@ -902,17 +941,152 @@
     EXPECT_EQ(NO_ERROR, ret);
 }
 
+TEST_F(BinderLibTest, WorkSourceUnsetByDefault)
+{
+    status_t ret;
+    Parcel data, reply;
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+    EXPECT_EQ(-1, reply.readInt32());
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceSet)
+{
+    status_t ret;
+    Parcel data, reply;
+    IPCThreadState::self()->clearCallingWorkSource();
+    int64_t previousWorkSource = IPCThreadState::self()->setCallingWorkSourceUid(100);
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+    EXPECT_EQ(100, reply.readInt32());
+    EXPECT_EQ(-1, previousWorkSource);
+    EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource());
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceSetWithoutPropagation)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    IPCThreadState::self()->setCallingWorkSourceUidWithoutPropagation(100);
+    EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+    EXPECT_EQ(-1, reply.readInt32());
+    EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceCleared)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    IPCThreadState::self()->setCallingWorkSourceUid(100);
+    int64_t token = IPCThreadState::self()->clearCallingWorkSource();
+    int32_t previousWorkSource = (int32_t)token;
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+    EXPECT_EQ(-1, reply.readInt32());
+    EXPECT_EQ(100, previousWorkSource);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceRestored)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    IPCThreadState::self()->setCallingWorkSourceUid(100);
+    int64_t token = IPCThreadState::self()->clearCallingWorkSource();
+    IPCThreadState::self()->restoreCallingWorkSource(token);
+
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+    EXPECT_EQ(100, reply.readInt32());
+    EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource());
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, PropagateFlagSet)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    IPCThreadState::self()->clearPropagateWorkSource();
+    IPCThreadState::self()->setCallingWorkSourceUid(100);
+    EXPECT_EQ(true, IPCThreadState::self()->shouldPropagateWorkSource());
+}
+
+TEST_F(BinderLibTest, PropagateFlagCleared)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    IPCThreadState::self()->setCallingWorkSourceUid(100);
+    IPCThreadState::self()->clearPropagateWorkSource();
+    EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+}
+
+TEST_F(BinderLibTest, PropagateFlagRestored)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    int token = IPCThreadState::self()->setCallingWorkSourceUid(100);
+    IPCThreadState::self()->restoreCallingWorkSource(token);
+
+    EXPECT_EQ(false, IPCThreadState::self()->shouldPropagateWorkSource());
+}
+
+TEST_F(BinderLibTest, WorkSourcePropagatedForAllFollowingBinderCalls)
+{
+    IPCThreadState::self()->setCallingWorkSourceUid(100);
+
+    Parcel data, reply;
+    status_t ret;
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+    Parcel data2, reply2;
+    status_t ret2;
+    data2.writeInterfaceToken(binderLibTestServiceName);
+    ret2 = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data2, &reply2);
+    EXPECT_EQ(100, reply2.readInt32());
+    EXPECT_EQ(NO_ERROR, ret2);
+}
+
+TEST_F(BinderLibTest, VectorSent) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+
+    std::vector<uint64_t> const testValue = { std::numeric_limits<uint64_t>::max(), 0, 200 };
+    data.writeUint64Vector(testValue);
+
+    status_t ret = server->transact(BINDER_LIB_TEST_ECHO_VECTOR, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+    std::vector<uint64_t> readValue;
+    ret = reply.readUint64Vector(&readValue);
+    EXPECT_EQ(readValue, testValue);
+}
+
 class BinderLibTestService : public BBinder
 {
     public:
-        BinderLibTestService(int32_t id)
+        explicit BinderLibTestService(int32_t id)
             : m_id(id)
             , m_nextServerId(id + 1)
             , m_serverStartRequested(false)
-            , m_callback(NULL)
+            , m_callback(nullptr)
         {
-            pthread_mutex_init(&m_serverWaitMutex, NULL);
-            pthread_cond_init(&m_serverWaitCond, NULL);
+            pthread_mutex_init(&m_serverWaitMutex, nullptr);
+            pthread_cond_init(&m_serverWaitCond, nullptr);
         }
         ~BinderLibTestService()
         {
@@ -920,11 +1094,11 @@
         }
 
         void processPendingCall() {
-            if (m_callback != NULL) {
+            if (m_callback != nullptr) {
                 Parcel data;
                 data.writeInt32(NO_ERROR);
                 m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY);
-                m_callback = NULL;
+                m_callback = nullptr;
             }
         }
 
@@ -943,7 +1117,7 @@
                 sp<IBinder> binder;
                 id = data.readInt32();
                 binder = data.readStrongBinder();
-                if (binder == NULL) {
+                if (binder == nullptr) {
                     return BAD_VALUE;
                 }
 
@@ -993,7 +1167,7 @@
                     } else {
                         reply->writeStrongBinder(m_serverStarted);
                         reply->writeInt32(serverid);
-                        m_serverStarted = NULL;
+                        m_serverStarted = nullptr;
                         ret = NO_ERROR;
                     }
                 } else if (ret >= 0) {
@@ -1008,7 +1182,7 @@
             case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
                 // Note: this transaction is only designed for use with a
                 // poll() server. See comments around epoll_wait().
-                if (m_callback != NULL) {
+                if (m_callback != nullptr) {
                     // A callback was already pending; this means that
                     // we received a second call while still processing
                     // the first one. Fail the test.
@@ -1016,7 +1190,7 @@
                     Parcel data2;
                     data2.writeInt32(UNKNOWN_ERROR);
 
-                    callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, NULL, TF_ONE_WAY);
+                    callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, nullptr, TF_ONE_WAY);
                 } else {
                     m_callback = data.readStrongBinder();
                     int32_t delayUs = data.readInt32();
@@ -1045,7 +1219,7 @@
                 Parcel data2, reply2;
                 sp<IBinder> binder;
                 binder = data.readStrongBinder();
-                if (binder == NULL) {
+                if (binder == nullptr) {
                     return BAD_VALUE;
                 }
                 data2.writeInt32(NO_ERROR);
@@ -1068,7 +1242,7 @@
                 reply->writeInt32(count);
                 for (int i = 0; i < count; i++) {
                     binder = data.readStrongBinder();
-                    if (binder == NULL) {
+                    if (binder == nullptr) {
                         return BAD_VALUE;
                     }
                     indirect_code = data.readInt32();
@@ -1101,11 +1275,11 @@
                 sp<IBinder> callback;
 
                 target = data.readStrongBinder();
-                if (target == NULL) {
+                if (target == nullptr) {
                     return BAD_VALUE;
                 }
                 callback = data.readStrongBinder();
-                if (callback == NULL) {
+                if (callback == nullptr) {
                     return BAD_VALUE;
                 }
                 ret = target->linkToDeath(testDeathRecipient);
@@ -1130,7 +1304,7 @@
                     return ret;
                 }
                 buf = data.readInplace(size);
-                if (buf == NULL) {
+                if (buf == nullptr) {
                     return BAD_VALUE;
                 }
                 ret = write(fd, buf, size);
@@ -1138,6 +1312,28 @@
                     return UNKNOWN_ERROR;
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION: {
+                int ret;
+                int32_t size;
+                const void *buf;
+                android::base::unique_fd fd;
+
+                ret = data.readUniqueParcelFileDescriptor(&fd);
+                if (ret != NO_ERROR) {
+                    return ret;
+                }
+                ret = data.readInt32(&size);
+                if (ret != NO_ERROR) {
+                    return ret;
+                }
+                buf = data.readInplace(size);
+                if (buf == nullptr) {
+                    return BAD_VALUE;
+                }
+                ret = write(fd.get(), buf, size);
+                if (ret != size) return UNKNOWN_ERROR;
+                return NO_ERROR;
+            }
             case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: {
                 int ret;
                 wp<IBinder> weak;
@@ -1147,7 +1343,7 @@
                 sp<IBinder> server = sm->getService(binderLibTestServiceName);
 
                 weak = data.readWeakBinder();
-                if (weak == NULL) {
+                if (weak == nullptr) {
                     return BAD_VALUE;
                 }
                 strong = weak.promote();
@@ -1156,7 +1352,7 @@
                 if (ret != NO_ERROR)
                     exit(EXIT_FAILURE);
 
-                if (strong == NULL) {
+                if (strong == nullptr) {
                     reply->setError(1);
                 }
                 return NO_ERROR;
@@ -1165,7 +1361,7 @@
                 alarm(10);
                 return NO_ERROR;
             case BINDER_LIB_TEST_EXIT_TRANSACTION:
-                while (wait(NULL) != -1 || errno != ECHILD)
+                while (wait(nullptr) != -1 || errno != ECHILD)
                     ;
                 exit(EXIT_SUCCESS);
             case BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION: {
@@ -1178,6 +1374,19 @@
                 }
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
+                data.enforceInterface(binderLibTestServiceName);
+                reply->writeInt32(IPCThreadState::self()->getCallingWorkSourceUid());
+                return NO_ERROR;
+            }
+            case BINDER_LIB_TEST_ECHO_VECTOR: {
+                std::vector<uint64_t> vector;
+                auto err = data.readUint64Vector(&vector);
+                if (err != NO_ERROR)
+                    return err;
+                reply->writeUint64Vector(vector);
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
             };
@@ -1237,7 +1446,7 @@
         }
         IPCThreadState::self()->flushCommands(); // flush BC_ENTER_LOOPER
 
-        epoll_fd = epoll_create1(0);
+        epoll_fd = epoll_create1(EPOLL_CLOEXEC);
         if (epoll_fd == -1) {
             return 1;
         }
@@ -1300,4 +1509,3 @@
     ProcessState::self()->startThreadPool();
     return RUN_ALL_TESTS();
 }
-
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 6a16e24..3b1db27 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -229,6 +229,7 @@
         IncrementUint32,
         IncrementInt64,
         IncrementUint64,
+        IncrementFloat,
         IncrementTwo,
         Last,
     };
@@ -259,6 +260,7 @@
     virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
     virtual status_t increment(int64_t a, int64_t* aPlusOne) const = 0;
     virtual status_t increment(uint64_t a, uint64_t* aPlusOne) const = 0;
+    virtual status_t increment(float a, float* aPlusOne) const = 0;
 
     // This tests that input/output parameter interleaving works correctly
     virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
@@ -353,6 +355,11 @@
         using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
         return callRemote<Signature>(Tag::IncrementUint64, a, aPlusOne);
     }
+    status_t increment(float a, float* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
+        return callRemote<Signature>(Tag::IncrementFloat, a, aPlusOne);
+    }
     status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         using Signature =
@@ -474,6 +481,11 @@
         *aPlusOne = a + 1;
         return NO_ERROR;
     }
+    status_t increment(float a, float* aPlusOne) const override {
+        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+        *aPlusOne = a + 1.0f;
+        return NO_ERROR;
+    }
     status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
         ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
         *aPlusOne = a + 1;
@@ -555,6 +567,10 @@
                 using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
                 return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
             }
+            case ISafeInterfaceTest::Tag::IncrementFloat: {
+                using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
+                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+            }
             case ISafeInterfaceTest::Tag::IncrementTwo: {
                 using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
                                                                    int32_t*) const;
@@ -804,6 +820,14 @@
     ASSERT_EQ(a + 1, aPlusOne);
 }
 
+TEST_F(SafeInterfaceTest, TestIncrementFloat) {
+    const float a = 1.0f;
+    float aPlusOne = 0.0f;
+    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+    ASSERT_EQ(NO_ERROR, result);
+    ASSERT_EQ(a + 1.0f, aPlusOne);
+}
+
 TEST_F(SafeInterfaceTest, TestIncrementTwo) {
     const int32_t a = 1;
     int32_t aPlusOne = 0;
diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp
index f6dd22d..ce99f59 100644
--- a/libs/binder/tests/binderTextOutputTest.cpp
+++ b/libs/binder/tests/binderTextOutputTest.cpp
@@ -28,15 +28,14 @@
 #include <binder/TextOutput.h>
 #include <binder/Debug.h>
 
-static void CheckMessage(const CapturedStderr& cap,
+static void CheckMessage(CapturedStderr& cap,
                          const char* expected,
                          bool singleline) {
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
+    cap.Stop();
+    std::string output = cap.str();
     if (singleline)
         output.erase(std::remove(output.begin(), output.end(), '\n'));
-    ASSERT_STREQ(output.c_str(), expected);
+    ASSERT_EQ(output, expected);
 }
 
 #define CHECK_LOG_(input, expect, singleline)    \
@@ -60,28 +59,22 @@
 TEST(TextOutput, HandlesStdEndl) {
     CapturedStderr cap;
     android::aerr << "foobar" << std::endl;
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_STREQ(output.c_str(), "foobar\n");
+    cap.Stop();
+    ASSERT_EQ(cap.str(), "foobar\n");
 }
 
 TEST(TextOutput, HandlesCEndl) {
     CapturedStderr cap;
     android::aerr << "foobar" << "\n";
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_STREQ(output.c_str(), "foobar\n");
+    cap.Stop();
+    ASSERT_EQ(cap.str(), "foobar\n");
 }
 
 TEST(TextOutput, HandlesAndroidEndl) {
     CapturedStderr cap;
     android::aerr << "foobar" << android::endl;
-    std::string output;
-    ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
-    android::base::ReadFdToString(cap.fd(), &output);
-    ASSERT_STREQ(output.c_str(), "foobar\n");
+    cap.Stop();
+    ASSERT_EQ(cap.str(), "foobar\n");
 }
 
 TEST(TextOutput, HandleEmptyString) {
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index bf41e0b..b790997 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -380,7 +380,7 @@
             // Caller specified the max latency in microseconds.
             // 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;
+                max_time_bucket = strtoull(argv[i+1], (char **)nullptr, 10) * 1000;
                 time_per_bucket = max_time_bucket / num_buckets;
                 i++;
             } else {
diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp
index c8f4697..f8922b0 100644
--- a/libs/binder/tests/binderValueTypeTest.cpp
+++ b/libs/binder/tests/binderValueTypeTest.cpp
@@ -22,7 +22,6 @@
 #include <vector>
 
 #include "android-base/file.h"
-#include "android-base/test_utils.h"
 #include <gtest/gtest.h>
 
 #include <binder/Parcel.h>
@@ -76,13 +75,13 @@
 
 VALUE_TYPE_TEST(bool, Boolean, true)
 VALUE_TYPE_TEST(int32_t, Int, 31337)
-VALUE_TYPE_TEST(int64_t, Long, 13370133701337l)
+VALUE_TYPE_TEST(int64_t, Long, 13370133701337L)
 VALUE_TYPE_TEST(double, Double, 3.14159265358979323846)
 VALUE_TYPE_TEST(String16, String, String16("Lovely"))
 
 VALUE_TYPE_VECTOR_TEST(bool, Boolean, true)
 VALUE_TYPE_VECTOR_TEST(int32_t, Int, 31337)
-VALUE_TYPE_VECTOR_TEST(int64_t, Long, 13370133701337l)
+VALUE_TYPE_VECTOR_TEST(int64_t, Long, 13370133701337L)
 VALUE_TYPE_VECTOR_TEST(double, Double, 3.14159265358979323846)
 VALUE_TYPE_VECTOR_TEST(String16, String, String16("Lovely"))
 
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index 13f03b1..ec9534a 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -218,7 +218,7 @@
   uint64_t m_total_time = 0;
   uint64_t m_miss = 0;
   bool tracing;
-  Results(bool _tracing) : tracing(_tracing) {
+  explicit Results(bool _tracing) : tracing(_tracing) {
   }
   inline bool miss_deadline(uint64_t nano) {
     return nano > deadline_us * 1000;
@@ -295,7 +295,7 @@
 
   no_inherent += reply.readInt32();
   no_sync += reply.readInt32();
-  return 0;
+  return nullptr;
 }
 
 // create a fifo thread to transact and wait it to finished
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
new file mode 100644
index 0000000..512b069
--- /dev/null
+++ b/libs/binderthreadstate/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libbinderthreadstate",
+    recovery_available: true,
+    vendor_available: false,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "IPCThreadStateBase.cpp",
+    ],
+
+    header_libs: [
+        "libbase_headers",
+        "libutils_headers",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    export_include_dirs: ["include"],
+
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libs/binderthreadstate/IPCThreadStateBase.cpp b/libs/binderthreadstate/IPCThreadStateBase.cpp
new file mode 100644
index 0000000..fede151
--- /dev/null
+++ b/libs/binderthreadstate/IPCThreadStateBase.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IPCThreadStateBase"
+
+#include <binderthreadstate/IPCThreadStateBase.h>
+#include <android-base/macros.h>
+
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+IPCThreadStateBase::IPCThreadStateBase() {
+    pthread_setspecific(gTLS, this);
+}
+
+IPCThreadStateBase* IPCThreadStateBase::self()
+{
+    if (gHaveTLS) {
+restart:
+        const pthread_key_t k = gTLS;
+        IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
+        if (st) return st;
+        return new IPCThreadStateBase;
+    }
+
+    pthread_mutex_lock(&gTLSMutex);
+    if (!gHaveTLS) {
+        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
+        if (key_create_value != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
+                    strerror(key_create_value));
+            return nullptr;
+        }
+        gHaveTLS = true;
+    }
+    pthread_mutex_unlock(&gTLSMutex);
+    goto restart;
+}
+
+void IPCThreadStateBase::pushCurrentState(CallState callState) {
+    mCallStateStack.emplace(callState);
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
+    ALOG_ASSERT(mCallStateStack.size > 0);
+    CallState val = mCallStateStack.top();
+    mCallStateStack.pop();
+    return val;
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
+    if (mCallStateStack.size() > 0) {
+        return mCallStateStack.top();
+    }
+    return CallState::NONE;
+}
+
+void IPCThreadStateBase::threadDestructor(void *st)
+{
+    IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
+    if (self) {
+        delete self;
+    }
+}
+
+}; // namespace android
diff --git a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
new file mode 100644
index 0000000..6fdcc84
--- /dev/null
+++ b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+#define BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+
+#include <stack>
+namespace android {
+
+class IPCThreadStateBase {
+public:
+    enum CallState {
+        HWBINDER,
+        BINDER,
+        NONE,
+    };
+    static IPCThreadStateBase* self();
+    void pushCurrentState(CallState callState);
+    CallState popCurrentState();
+    CallState getCurrentBinderCallState();
+
+private:
+    IPCThreadStateBase();
+    static void threadDestructor(void *st);
+
+    std::stack<CallState> mCallStateStack;
+};
+
+}; // namespace android
+
+#endif // BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
new file mode 100644
index 0000000..28cb138
--- /dev/null
+++ b/libs/cputimeinstate/Android.bp
@@ -0,0 +1,30 @@
+cc_library {
+    name: "libtimeinstate",
+    srcs: ["cputimeinstate.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbpf",
+        "libbpf_android",
+        "liblog",
+        "libnetdutils"
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+}
+
+cc_test {
+    name: "libtimeinstate_test",
+    srcs: ["testtimeinstate.cpp"],
+    shared_libs: [
+        "libtimeinstate",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+}
+
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
new file mode 100644
index 0000000..5fd4a95
--- /dev/null
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libtimeinstate"
+
+#include "cputimeinstate.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
+#include <libbpf.h>
+#include <log/log.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace bpf {
+
+struct time_key_t {
+    uint32_t uid;
+    uint32_t freq;
+};
+
+struct val_t {
+    uint64_t ar[100];
+};
+
+static std::mutex gInitializedMutex;
+static bool gInitialized = false;
+static uint32_t gNPolicies = 0;
+static std::vector<std::vector<uint32_t>> gPolicyFreqs;
+static std::vector<std::vector<uint32_t>> gPolicyCpus;
+static std::set<uint32_t> gAllFreqs;
+static unique_fd gMapFd;
+
+static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
+    std::string data;
+
+    if (!android::base::ReadFileToString(path, &data)) return false;
+
+    auto strings = android::base::Split(data, " \n");
+    for (const auto &s : strings) {
+        if (s.empty()) continue;
+        uint32_t n;
+        if (!android::base::ParseUint(s, &n)) return false;
+        out->emplace_back(n);
+    }
+    return true;
+}
+
+static int isPolicyFile(const struct dirent *d) {
+    return android::base::StartsWith(d->d_name, "policy");
+}
+
+static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2) {
+    uint32_t policyN1, policyN2;
+    if (sscanf((*d1)->d_name, "policy%" SCNu32 "", &policyN1) != 1 ||
+        sscanf((*d2)->d_name, "policy%" SCNu32 "", &policyN2) != 1)
+        return 0;
+    return policyN1 - policyN2;
+}
+
+static bool initGlobals() {
+    std::lock_guard<std::mutex> guard(gInitializedMutex);
+    if (gInitialized) return true;
+
+    struct dirent **dirlist;
+    const char basepath[] = "/sys/devices/system/cpu/cpufreq";
+    int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
+    if (ret == -1) return false;
+    gNPolicies = ret;
+
+    std::vector<std::string> policyFileNames;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        policyFileNames.emplace_back(dirlist[i]->d_name);
+        free(dirlist[i]);
+    }
+    free(dirlist);
+
+    for (const auto &policy : policyFileNames) {
+        std::vector<uint32_t> freqs;
+        for (const auto &name : {"available", "boost"}) {
+            std::string path =
+                    StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
+            if (!readNumbersFromFile(path, &freqs)) return false;
+        }
+        std::sort(freqs.begin(), freqs.end());
+        gPolicyFreqs.emplace_back(freqs);
+
+        for (auto freq : freqs) gAllFreqs.insert(freq);
+
+        std::vector<uint32_t> cpus;
+        std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
+        if (!readNumbersFromFile(path, &cpus)) return false;
+        gPolicyCpus.emplace_back(cpus);
+    }
+
+    gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
+    if (gMapFd < 0) return false;
+
+    gInitialized = true;
+    return true;
+}
+
+static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+    std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
+                                    eventType.c_str(), eventName.c_str());
+    int prog_fd = bpf_obj_get(path.c_str());
+    if (prog_fd < 0) return false;
+    return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
+}
+
+// Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
+// Returns true on success, false otherwise.
+// Tracking is active only once a live process has successfully called this function; if the calling
+// process dies then it must be called again to resume tracking.
+// This function should *not* be called while tracking is already active; doing so is unnecessary
+// and can lead to accounting errors.
+bool startTrackingUidCpuFreqTimes() {
+    return attachTracepointProgram("sched", "sched_switch") &&
+            attachTracepointProgram("power", "cpu_frequency");
+}
+
+// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
+// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
+// using the format:
+// [[t0_0, t0_1, ...],
+//  [t1_0, t1_1, ...], ...]
+// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
+bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
+    if (!gInitialized && !initGlobals()) return false;
+    time_key_t key = {.uid = uid, .freq = 0};
+
+    freqTimes->clear();
+    freqTimes->resize(gNPolicies);
+    std::vector<uint32_t> idxs(gNPolicies, 0);
+
+    val_t value;
+    for (uint32_t freq : gAllFreqs) {
+        key.freq = freq;
+        int ret = findMapEntry(gMapFd, &key, &value);
+        if (ret) {
+            if (errno == ENOENT)
+                memset(&value.ar, 0, sizeof(value.ar));
+            else
+                return false;
+        }
+        for (uint32_t i = 0; i < gNPolicies; ++i) {
+            if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
+            uint64_t time = 0;
+            for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
+            idxs[i] += 1;
+            (*freqTimes)[i].emplace_back(time);
+        }
+    }
+
+    return true;
+}
+
+// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
+// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
+// vectors of vectors using the format:
+// { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+//   uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
+bool getUidsCpuFreqTimes(
+        std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
+    if (!gInitialized && !initGlobals()) return false;
+
+    int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
+    if (fd < 0) return false;
+    BpfMap<time_key_t, val_t> m(fd);
+
+    std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        std::unordered_map<uint32_t, uint32_t> freqIdxs;
+        for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
+        policyFreqIdxs.emplace_back(freqIdxs);
+    }
+
+    auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
+                                             const BpfMap<time_key_t, val_t> &) {
+        if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
+            (*freqTimeMap)[key.uid].resize(gNPolicies);
+            for (uint32_t i = 0; i < gNPolicies; ++i) {
+                (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
+            }
+        }
+
+        for (size_t policy = 0; policy < gNPolicies; ++policy) {
+            for (const auto &cpu : gPolicyCpus[policy]) {
+                auto freqIdx = policyFreqIdxs[policy][key.freq];
+                (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
+            }
+        }
+        return android::netdutils::status::ok;
+    };
+    return isOk(m.iterateWithValue(fn));
+}
+
+// Clear all time in state data for a given uid. Returns false on error, true otherwise.
+bool clearUidCpuFreqTimes(uint32_t uid) {
+    if (!gInitialized && !initGlobals()) return false;
+    time_key_t key = {.uid = uid, .freq = 0};
+
+    std::vector<uint32_t> idxs(gNPolicies, 0);
+    for (auto freq : gAllFreqs) {
+        key.freq = freq;
+        if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
+    }
+    return true;
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
new file mode 100644
index 0000000..9f6103e
--- /dev/null
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace bpf {
+
+bool startTrackingUidCpuFreqTimes();
+bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
+bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
+bool clearUidCpuFreqTimes(unsigned int uid);
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
new file mode 100644
index 0000000..9837865
--- /dev/null
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -0,0 +1,58 @@
+
+#include <unordered_map>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <cputimeinstate.h>
+
+namespace android {
+namespace bpf {
+
+using std::vector;
+
+TEST(TimeInStateTest, SingleUid) {
+    vector<vector<uint64_t>> times;
+    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
+    EXPECT_FALSE(times.empty());
+}
+
+TEST(TimeInStateTest, AllUid) {
+    vector<size_t> sizes;
+    std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
+    ASSERT_TRUE(getUidsCpuFreqTimes(&map));
+
+    ASSERT_FALSE(map.empty());
+
+    auto firstEntry = map.begin()->second;
+    for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
+
+    for (const auto &vec : map) {
+        ASSERT_EQ(vec.second.size(), sizes.size());
+        for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+    }
+}
+
+TEST(TimeInStateTest, RemoveUid) {
+    vector<vector<uint64_t>> times, times2;
+    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
+    ASSERT_FALSE(times.empty());
+
+    uint64_t sum = 0;
+    for (size_t i = 0; i < times.size(); ++i) {
+        for (auto x : times[i]) sum += x;
+    }
+    ASSERT_GT(sum, (uint64_t)0);
+
+    ASSERT_TRUE(clearUidCpuFreqTimes(0));
+
+    ASSERT_TRUE(getUidCpuFreqTimes(0, &times2));
+    ASSERT_EQ(times2.size(), times.size());
+    for (size_t i = 0; i < times.size(); ++i) {
+        ASSERT_EQ(times2[i].size(), times[i].size());
+        for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
+    }
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 8b2f842..40f6b43 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -31,11 +31,14 @@
         "/system/bin/mediaextractor", // media.extractor
         "/system/bin/mediametrics", // media.metrics
         "/system/bin/mediaserver",
+        "/system/bin/netd",
+        "/system/bin/vold",
         "/system/bin/sdcard",
         "/system/bin/statsd",
         "/system/bin/surfaceflinger",
         "/system/bin/vehicle_network_service",
         "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
+        "/apex/com.android.media.swcodec/bin/mediaswcodec", // media.swcodec
         NULL,
 };
 
@@ -46,10 +49,16 @@
         "android.hardware.bluetooth@1.0::IBluetoothHci",
         "android.hardware.camera.provider@2.4::ICameraProvider",
         "android.hardware.drm@1.0::IDrmFactory",
+        "android.hardware.graphics.allocator@2.0::IAllocator",
         "android.hardware.graphics.composer@2.1::IComposer",
+        "android.hardware.health@2.0::IHealth",
+        "android.hardware.media.c2@1.0::IComponentStore",
         "android.hardware.media.omx@1.0::IOmx",
         "android.hardware.media.omx@1.0::IOmxStore",
+        "android.hardware.power@1.3::IPower",
+        "android.hardware.power.stats@1.0::IPowerStats",
         "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.thermal@2.0::IThermal",
         "android.hardware.vr@1.0::IVr",
         NULL,
 };
@@ -102,13 +111,15 @@
 }
 
 bool IsZygote(int pid) {
-    static const std::string kZygotePrefix = "zygote";
-
     std::string cmdline;
     if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
                                          &cmdline)) {
         return true;
     }
 
-    return (cmdline.find(kZygotePrefix) == 0);
+    // cmdline has embedded nulls; only consider argv[0].
+    cmdline = std::string(cmdline.c_str());
+
+    return cmdline == "zygote" || cmdline == "zygote64" || cmdline == "usap32" ||
+            cmdline == "usap64";
 }
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 4da30e9..56521bf 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -16,13 +16,20 @@
     name: "libgraphicsenv",
 
     srcs: [
+        "GpuStatsInfo.cpp",
         "GraphicsEnv.cpp",
+        "IGpuService.cpp"
     ],
 
     cflags: ["-Wall", "-Werror"],
 
     shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libdl_android",
         "liblog",
+        "libutils",
     ],
 
     export_include_dirs: ["include"],
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
new file mode 100644
index 0000000..4a801be
--- /dev/null
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
+#include <graphicsenv/GpuStatsInfo.h>
+
+namespace android {
+
+using base::StringAppendF;
+
+status_t GpuStatsGlobalInfo::writeToParcel(Parcel* parcel) const {
+    status_t status;
+    if ((status = parcel->writeUtf8AsUtf16(driverPackageName)) != OK) return status;
+    if ((status = parcel->writeUtf8AsUtf16(driverVersionName)) != OK) return status;
+    if ((status = parcel->writeUint64(driverVersionCode)) != OK) return status;
+    if ((status = parcel->writeInt64(driverBuildTime)) != OK) return status;
+    if ((status = parcel->writeInt32(glLoadingCount)) != OK) return status;
+    if ((status = parcel->writeInt32(glLoadingFailureCount)) != OK) return status;
+    if ((status = parcel->writeInt32(vkLoadingCount)) != OK) return status;
+    if ((status = parcel->writeInt32(vkLoadingFailureCount)) != OK) return status;
+    if ((status = parcel->writeInt32(vulkanVersion)) != OK) return status;
+    if ((status = parcel->writeInt32(cpuVulkanVersion)) != OK) return status;
+    if ((status = parcel->writeInt32(glesVersion)) != OK) return status;
+    if ((status = parcel->writeInt32(angleLoadingCount)) != OK) return status;
+    if ((status = parcel->writeInt32(angleLoadingFailureCount)) != OK) return status;
+    return OK;
+}
+
+status_t GpuStatsGlobalInfo::readFromParcel(const Parcel* parcel) {
+    status_t status;
+    if ((status = parcel->readUtf8FromUtf16(&driverPackageName)) != OK) return status;
+    if ((status = parcel->readUtf8FromUtf16(&driverVersionName)) != OK) return status;
+    if ((status = parcel->readUint64(&driverVersionCode)) != OK) return status;
+    if ((status = parcel->readInt64(&driverBuildTime)) != OK) return status;
+    if ((status = parcel->readInt32(&glLoadingCount)) != OK) return status;
+    if ((status = parcel->readInt32(&glLoadingFailureCount)) != OK) return status;
+    if ((status = parcel->readInt32(&vkLoadingCount)) != OK) return status;
+    if ((status = parcel->readInt32(&vkLoadingFailureCount)) != OK) return status;
+    if ((status = parcel->readInt32(&vulkanVersion)) != OK) return status;
+    if ((status = parcel->readInt32(&cpuVulkanVersion)) != OK) return status;
+    if ((status = parcel->readInt32(&glesVersion)) != OK) return status;
+    if ((status = parcel->readInt32(&angleLoadingCount)) != OK) return status;
+    if ((status = parcel->readInt32(&angleLoadingFailureCount)) != OK) return status;
+    return OK;
+}
+
+std::string GpuStatsGlobalInfo::toString() const {
+    std::string result;
+    StringAppendF(&result, "driverPackageName = %s\n", driverPackageName.c_str());
+    StringAppendF(&result, "driverVersionName = %s\n", driverVersionName.c_str());
+    StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
+    StringAppendF(&result, "driverBuildTime = %" PRId64 "\n", driverBuildTime);
+    StringAppendF(&result, "glLoadingCount = %d\n", glLoadingCount);
+    StringAppendF(&result, "glLoadingFailureCount = %d\n", glLoadingFailureCount);
+    StringAppendF(&result, "angleLoadingCount = %d\n", angleLoadingCount);
+    StringAppendF(&result, "angleLoadingFailureCount = %d\n", angleLoadingFailureCount);
+    StringAppendF(&result, "vkLoadingCount = %d\n", vkLoadingCount);
+    StringAppendF(&result, "vkLoadingFailureCount = %d\n", vkLoadingFailureCount);
+    StringAppendF(&result, "vulkanVersion = %d\n", vulkanVersion);
+    StringAppendF(&result, "cpuVulkanVersion = %d\n", cpuVulkanVersion);
+    StringAppendF(&result, "glesVersion = %d\n", glesVersion);
+    return result;
+}
+
+status_t GpuStatsAppInfo::writeToParcel(Parcel* parcel) const {
+    status_t status;
+    if ((status = parcel->writeUtf8AsUtf16(appPackageName)) != OK) return status;
+    if ((status = parcel->writeUint64(driverVersionCode)) != OK) return status;
+    if ((status = parcel->writeInt64Vector(glDriverLoadingTime)) != OK) return status;
+    if ((status = parcel->writeInt64Vector(vkDriverLoadingTime)) != OK) return status;
+    if ((status = parcel->writeInt64Vector(angleDriverLoadingTime)) != OK) return status;
+    if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status;
+    return OK;
+}
+
+status_t GpuStatsAppInfo::readFromParcel(const Parcel* parcel) {
+    status_t status;
+    if ((status = parcel->readUtf8FromUtf16(&appPackageName)) != OK) return status;
+    if ((status = parcel->readUint64(&driverVersionCode)) != OK) return status;
+    if ((status = parcel->readInt64Vector(&glDriverLoadingTime)) != OK) return status;
+    if ((status = parcel->readInt64Vector(&vkDriverLoadingTime)) != OK) return status;
+    if ((status = parcel->readInt64Vector(&angleDriverLoadingTime)) != OK) return status;
+    if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status;
+    return OK;
+}
+
+std::string GpuStatsAppInfo::toString() const {
+    std::string result;
+    StringAppendF(&result, "appPackageName = %s\n", appPackageName.c_str());
+    StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
+    StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse);
+    result.append("glDriverLoadingTime:");
+    for (int32_t loadingTime : glDriverLoadingTime) {
+        StringAppendF(&result, " %d", loadingTime);
+    }
+    result.append("\n");
+    result.append("angleDriverLoadingTime:");
+    for (int32_t loadingTime : angleDriverLoadingTime) {
+        StringAppendF(&result, " %d", loadingTime);
+    }
+    result.append("\n");
+    result.append("vkDriverLoadingTime:");
+    for (int32_t loadingTime : vkDriverLoadingTime) {
+        StringAppendF(&result, " %d", loadingTime);
+    }
+    result.append("\n");
+    return result;
+}
+
+} // namespace android
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 961f101..bb9e263 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -14,96 +14,626 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 //#define LOG_NDEBUG 1
 #define LOG_TAG "GraphicsEnv"
+
 #include <graphicsenv/GraphicsEnv.h>
 
-#include <mutex>
+#include <dlfcn.h>
+#include <unistd.h>
 
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
 #include <android/dlext.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <graphicsenv/IGpuService.h>
 #include <log/log.h>
+#include <sys/prctl.h>
+#include <utils/Trace.h>
+
+#include <memory>
+#include <string>
+#include <thread>
 
 // TODO(b/37049319) Get this from a header once one exists
 extern "C" {
-  android_namespace_t* android_get_exported_namespace(const char*);
-  android_namespace_t* android_create_namespace(const char* name,
-                                                const char* ld_library_path,
-                                                const char* default_library_path,
-                                                uint64_t type,
-                                                const char* permitted_when_isolated_path,
-                                                android_namespace_t* parent);
+android_namespace_t* android_get_exported_namespace(const char*);
+android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
+                                              const char* default_library_path, uint64_t type,
+                                              const char* permitted_when_isolated_path,
+                                              android_namespace_t* parent);
+bool android_link_namespaces(android_namespace_t* from, android_namespace_t* to,
+                             const char* shared_libs_sonames);
 
-  enum {
-     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
-     ANDROID_NAMESPACE_TYPE_SHARED = 2,
-  };
+enum {
+    ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+    ANDROID_NAMESPACE_TYPE_SHARED = 2,
+};
 }
 
+// TODO(ianelliott@): Get the following from an ANGLE header:
+#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
+// Version-2 API:
+typedef bool (*fpANGLEGetFeatureSupportUtilAPIVersion)(unsigned int* versionToUse);
+typedef bool (*fpANGLEAndroidParseRulesString)(const char* rulesString, void** rulesHandle,
+                                               int* rulesVersion);
+typedef bool (*fpANGLEGetSystemInfo)(void** handle);
+typedef bool (*fpANGLEAddDeviceInfoToSystemInfo)(const char* deviceMfr, const char* deviceModel,
+                                                 void* handle);
+typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVersion,
+                                                  void* systemInfoHandle, const char* appName);
+typedef bool (*fpANGLEFreeRulesHandle)(void* handle);
+typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle);
+
 namespace android {
 
+enum NativeLibrary {
+    LLNDK = 0,
+    VNDKSP = 1,
+};
+
+static constexpr const char* kNativeLibrariesSystemConfigPath[] = {"/etc/llndk.libraries.txt",
+                                                                   "/etc/vndksp.libraries.txt"};
+
+static std::string vndkVersionStr() {
+#ifdef __BIONIC__
+    std::string version = android::base::GetProperty("ro.vndk.version", "");
+    if (version != "" && version != "current") {
+        return "." + version;
+    }
+#endif
+    return "";
+}
+
+static void insertVndkVersionStr(std::string* fileName) {
+    LOG_ALWAYS_FATAL_IF(!fileName, "fileName should never be nullptr");
+    size_t insertPos = fileName->find_last_of(".");
+    if (insertPos == std::string::npos) {
+        insertPos = fileName->length();
+    }
+    fileName->insert(insertPos, vndkVersionStr());
+}
+
+static bool readConfig(const std::string& configFile, std::vector<std::string>* soNames) {
+    // Read list of public native libraries from the config file.
+    std::string fileContent;
+    if (!base::ReadFileToString(configFile, &fileContent)) {
+        return false;
+    }
+
+    std::vector<std::string> lines = base::Split(fileContent, "\n");
+
+    for (auto& line : lines) {
+        auto trimmedLine = base::Trim(line);
+        if (!trimmedLine.empty()) {
+            soNames->push_back(trimmedLine);
+        }
+    }
+
+    return true;
+}
+
+static const std::string getSystemNativeLibraries(NativeLibrary type) {
+    static const char* androidRootEnv = getenv("ANDROID_ROOT");
+    static const std::string rootDir = androidRootEnv != nullptr ? androidRootEnv : "/system";
+
+    std::string nativeLibrariesSystemConfig = rootDir + kNativeLibrariesSystemConfigPath[type];
+
+    insertVndkVersionStr(&nativeLibrariesSystemConfig);
+
+    std::vector<std::string> soNames;
+    if (!readConfig(nativeLibrariesSystemConfig, &soNames)) {
+        ALOGE("Failed to retrieve library names from %s", nativeLibrariesSystemConfig.c_str());
+        return "";
+    }
+
+    return base::Join(soNames, ':');
+}
+
 /*static*/ GraphicsEnv& GraphicsEnv::getInstance() {
     static GraphicsEnv env;
     return env;
 }
 
-void GraphicsEnv::setDriverPath(const std::string path) {
-    if (!mDriverPath.empty()) {
-        ALOGV("ignoring attempt to change driver path from '%s' to '%s'",
-                mDriverPath.c_str(), path.c_str());
-        return;
+int GraphicsEnv::getCanLoadSystemLibraries() {
+    if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
+        // Return an integer value since this crosses library boundaries
+        return 1;
     }
-    ALOGV("setting driver path to '%s'", path.c_str());
-    mDriverPath = path;
+    return 0;
 }
 
-void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) {
+void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
+                                                 const std::string sphalLibraries) {
+    if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
+        ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries "
+              "from '%s' to '%s'",
+              mDriverPath.c_str(), path.c_str(), mSphalLibraries.c_str(), sphalLibraries.c_str());
+        return;
+    }
+    ALOGV("setting driver path to '%s' and sphal libraries to '%s'", path.c_str(),
+          sphalLibraries.c_str());
+    mDriverPath = path;
+    mSphalLibraries = sphalLibraries;
+}
+
+void GraphicsEnv::hintActivityLaunch() {
+    ATRACE_CALL();
+
+    std::thread trySendGpuStatsThread([this]() {
+        // If there's already graphics driver preloaded in the process, just send
+        // the stats info to GpuStats directly through async binder.
+        std::lock_guard<std::mutex> lock(mStatsLock);
+        if (mGpuStats.glDriverToSend) {
+            mGpuStats.glDriverToSend = false;
+            sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
+        }
+        if (mGpuStats.vkDriverToSend) {
+            mGpuStats.vkDriverToSend = false;
+            sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
+        }
+    });
+    trySendGpuStatsThread.detach();
+}
+
+void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
+                              const std::string& driverVersionName, uint64_t driverVersionCode,
+                              int64_t driverBuildTime, const std::string& appPackageName,
+                              const int vulkanVersion) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    ALOGV("setGpuStats:\n"
+          "\tdriverPackageName[%s]\n"
+          "\tdriverVersionName[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
+          "\tappPackageName[%s]\n"
+          "\tvulkanVersion[%d]\n",
+          driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+          appPackageName.c_str(), vulkanVersion);
+
+    mGpuStats.driverPackageName = driverPackageName;
+    mGpuStats.driverVersionName = driverVersionName;
+    mGpuStats.driverVersionCode = driverVersionCode;
+    mGpuStats.driverBuildTime = driverBuildTime;
+    mGpuStats.appPackageName = appPackageName;
+    mGpuStats.vulkanVersion = vulkanVersion;
+}
+
+void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    switch (driver) {
+        case GraphicsEnv::Driver::GL:
+        case GraphicsEnv::Driver::GL_UPDATED:
+        case GraphicsEnv::Driver::ANGLE: {
+            if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE ||
+                mGpuStats.glDriverToLoad == GraphicsEnv::Driver::GL) {
+                mGpuStats.glDriverToLoad = driver;
+                break;
+            }
+
+            if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) {
+                mGpuStats.glDriverFallback = driver;
+            }
+            break;
+        }
+        case Driver::VULKAN:
+        case Driver::VULKAN_UPDATED: {
+            if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE ||
+                mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::VULKAN) {
+                mGpuStats.vkDriverToLoad = driver;
+                break;
+            }
+
+            if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) {
+                mGpuStats.vkDriverFallback = driver;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isDriverLoaded,
+                                  int64_t driverLoadingTime) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    const bool doNotSend = mGpuStats.appPackageName.empty();
+    if (api == GraphicsEnv::Api::API_GL) {
+        if (doNotSend) mGpuStats.glDriverToSend = true;
+        mGpuStats.glDriverLoadingTime = driverLoadingTime;
+    } else {
+        if (doNotSend) mGpuStats.vkDriverToSend = true;
+        mGpuStats.vkDriverLoadingTime = driverLoadingTime;
+    }
+
+    sendGpuStatsLocked(api, isDriverLoaded, driverLoadingTime);
+}
+
+static sp<IGpuService> getGpuService() {
+    const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
+    if (!binder) {
+        ALOGE("Failed to get gpu service");
+        return nullptr;
+    }
+
+    return interface_cast<IGpuService>(binder);
+}
+
+void GraphicsEnv::setTargetStats(const Stats stats, const uint64_t value) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mStatsLock);
+    const sp<IGpuService> gpuService = getGpuService();
+    if (gpuService) {
+        gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats,
+                                   value);
+    }
+}
+
+void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded,
+                                     int64_t driverLoadingTime) {
+    ATRACE_CALL();
+
+    // Do not sendGpuStats for those skipping the GraphicsEnvironment setup
+    if (mGpuStats.appPackageName.empty()) return;
+
+    ALOGV("sendGpuStats:\n"
+          "\tdriverPackageName[%s]\n"
+          "\tdriverVersionName[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
+          "\tappPackageName[%s]\n"
+          "\tvulkanVersion[%d]\n"
+          "\tapi[%d]\n"
+          "\tisDriverLoaded[%d]\n"
+          "\tdriverLoadingTime[%" PRId64 "]",
+          mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
+          mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
+          mGpuStats.vulkanVersion, static_cast<int32_t>(api), isDriverLoaded, driverLoadingTime);
+
+    GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE;
+    bool isIntendedDriverLoaded = false;
+    if (api == GraphicsEnv::Api::API_GL) {
+        driver = mGpuStats.glDriverToLoad;
+        isIntendedDriverLoaded =
+                isDriverLoaded && (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE);
+    } else {
+        driver = mGpuStats.vkDriverToLoad;
+        isIntendedDriverLoaded =
+                isDriverLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE);
+    }
+
+    const sp<IGpuService> gpuService = getGpuService();
+    if (gpuService) {
+        gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
+                                mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
+                                mGpuStats.appPackageName, mGpuStats.vulkanVersion, driver,
+                                isIntendedDriverLoaded, driverLoadingTime);
+    }
+}
+
+void* GraphicsEnv::loadLibrary(std::string name) {
+    const android_dlextinfo dlextinfo = {
+            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+            .library_namespace = getAngleNamespace(),
+    };
+
+    std::string libName = std::string("lib") + name + "_angle.so";
+
+    void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+
+    if (so) {
+        ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so);
+        return so;
+    } else {
+        ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror());
+    }
+
+    return nullptr;
+}
+
+bool GraphicsEnv::checkAngleRules(void* so) {
+    char manufacturer[PROPERTY_VALUE_MAX];
+    char model[PROPERTY_VALUE_MAX];
+    property_get("ro.product.manufacturer", manufacturer, "UNSET");
+    property_get("ro.product.model", model, "UNSET");
+
+    auto ANGLEGetFeatureSupportUtilAPIVersion =
+            (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so,
+                                                          "ANGLEGetFeatureSupportUtilAPIVersion");
+
+    if (!ANGLEGetFeatureSupportUtilAPIVersion) {
+        ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function");
+        return false;
+    }
+
+    // Negotiate the interface version by requesting most recent known to the platform
+    unsigned int versionToUse = CURRENT_ANGLE_API_VERSION;
+    if (!(ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) {
+        ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, "
+              "requested version %u",
+              versionToUse);
+        return false;
+    }
+
+    // Add and remove versions below as needed
+    bool useAngle = false;
+    switch (versionToUse) {
+        case 2: {
+            ALOGV("Using version %d of ANGLE feature-support library", versionToUse);
+            void* rulesHandle = nullptr;
+            int rulesVersion = 0;
+            void* systemInfoHandle = nullptr;
+
+            // Get the symbols for the feature-support-utility library:
+#define GET_SYMBOL(symbol)                                                 \
+    fp##symbol symbol = (fp##symbol)dlsym(so, #symbol);                    \
+    if (!symbol) {                                                         \
+        ALOGW("Cannot find " #symbol " in ANGLE feature-support library"); \
+        break;                                                             \
+    }
+            GET_SYMBOL(ANGLEAndroidParseRulesString);
+            GET_SYMBOL(ANGLEGetSystemInfo);
+            GET_SYMBOL(ANGLEAddDeviceInfoToSystemInfo);
+            GET_SYMBOL(ANGLEShouldBeUsedForApplication);
+            GET_SYMBOL(ANGLEFreeRulesHandle);
+            GET_SYMBOL(ANGLEFreeSystemInfoHandle);
+
+            // Parse the rules, obtain the SystemInfo, and evaluate the
+            // application against the rules:
+            if (!(ANGLEAndroidParseRulesString)(mRulesBuffer.data(), &rulesHandle, &rulesVersion)) {
+                ALOGW("ANGLE feature-support library cannot parse rules file");
+                break;
+            }
+            if (!(ANGLEGetSystemInfo)(&systemInfoHandle)) {
+                ALOGW("ANGLE feature-support library cannot obtain SystemInfo");
+                break;
+            }
+            if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer, model, systemInfoHandle)) {
+                ALOGW("ANGLE feature-support library cannot add device info to SystemInfo");
+                break;
+            }
+            useAngle = (ANGLEShouldBeUsedForApplication)(rulesHandle, rulesVersion,
+                                                         systemInfoHandle, mAngleAppName.c_str());
+            (ANGLEFreeRulesHandle)(rulesHandle);
+            (ANGLEFreeSystemInfoHandle)(systemInfoHandle);
+        } break;
+
+        default:
+            ALOGW("Version %u of ANGLE feature-support library is NOT supported.", versionToUse);
+    }
+
+    ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+    return useAngle;
+}
+
+bool GraphicsEnv::shouldUseAngle(std::string appName) {
+    if (appName != mAngleAppName) {
+        // Make sure we are checking the app we were init'ed for
+        ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(),
+              appName.c_str());
+        return false;
+    }
+
+    return shouldUseAngle();
+}
+
+bool GraphicsEnv::shouldUseAngle() {
+    // Make sure we are init'ed
+    if (mAngleAppName.empty()) {
+        ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
+        return false;
+    }
+
+    return (mUseAngle == YES) ? true : false;
+}
+
+void GraphicsEnv::updateUseAngle() {
+    mUseAngle = NO;
+
+    const char* ANGLE_PREFER_ANGLE = "angle";
+    const char* ANGLE_PREFER_NATIVE = "native";
+
+    if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
+        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+        mUseAngle = YES;
+    } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
+        ALOGV("User set \"Developer Options\" to force the use of Native");
+        mUseAngle = NO;
+    } else {
+        // The "Developer Options" value wasn't set to force the use of ANGLE.  Need to temporarily
+        // load ANGLE and call the updatable opt-in/out logic:
+        void* featureSo = loadLibrary("feature_support");
+        if (featureSo) {
+            ALOGV("loaded ANGLE's opt-in/out logic from namespace");
+            mUseAngle = checkAngleRules(featureSo) ? YES : NO;
+            dlclose(featureSo);
+            featureSo = nullptr;
+        } else {
+            ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE.");
+        }
+    }
+}
+
+void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
+                               const std::string developerOptIn, const int rulesFd,
+                               const long rulesOffset, const long rulesLength) {
+    if (mUseAngle != UNKNOWN) {
+        // We've already figured out an answer for this app, so just return.
+        ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(),
+              (mUseAngle == YES) ? "true" : "false");
+        return;
+    }
+
+    ALOGV("setting ANGLE path to '%s'", path.c_str());
+    mAnglePath = path;
+    ALOGV("setting ANGLE app name to '%s'", appName.c_str());
+    mAngleAppName = appName;
+    ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
+    mAngleDeveloperOptIn = developerOptIn;
+
+    lseek(rulesFd, rulesOffset, SEEK_SET);
+    mRulesBuffer = std::vector<char>(rulesLength + 1);
+    ssize_t numBytesRead = read(rulesFd, mRulesBuffer.data(), rulesLength);
+    if (numBytesRead < 0) {
+        ALOGE("Cannot read rules file: numBytesRead = %zd", numBytesRead);
+        numBytesRead = 0;
+    } else if (numBytesRead == 0) {
+        ALOGW("Empty rules file");
+    }
+    if (numBytesRead != rulesLength) {
+        ALOGW("Did not read all of the necessary bytes from the rules file."
+              "expected: %ld, got: %zd",
+              rulesLength, numBytesRead);
+    }
+    mRulesBuffer[numBytesRead] = '\0';
+
+    // Update the current status of whether we should use ANGLE or not
+    updateUseAngle();
+}
+
+void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
     if (mLayerPaths.empty()) {
         mLayerPaths = layerPaths;
         mAppNamespace = appNamespace;
     } else {
         ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
-                layerPaths.c_str(), appNamespace);
+              layerPaths.c_str(), appNamespace);
     }
 }
 
-android_namespace_t* GraphicsEnv::getAppNamespace() {
+NativeLoaderNamespace* GraphicsEnv::getAppNamespace() {
     return mAppNamespace;
 }
 
-const std::string GraphicsEnv::getLayerPaths(){
+std::string& GraphicsEnv::getAngleAppName() {
+    return mAngleAppName;
+}
+
+const std::string& GraphicsEnv::getLayerPaths() {
     return mLayerPaths;
 }
 
-const std::string GraphicsEnv::getDebugLayers() {
+const std::string& GraphicsEnv::getDebugLayers() {
     return mDebugLayers;
 }
 
+const std::string& GraphicsEnv::getDebugLayersGLES() {
+    return mDebugLayersGLES;
+}
+
 void GraphicsEnv::setDebugLayers(const std::string layers) {
     mDebugLayers = layers;
 }
 
+void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
+    mDebugLayersGLES = layers;
+}
+
+// Return true if all the required libraries from vndk and sphal namespace are
+// linked to the Game Driver namespace correctly.
+bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
+    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
+    if (llndkLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
+        ALOGE("Failed to link default namespace[%s]", dlerror());
+        return false;
+    }
+
+    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
+    if (vndkspLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
+        ALOGE("Failed to link vndk namespace[%s]", dlerror());
+        return false;
+    }
+
+    if (mSphalLibraries.empty()) {
+        return true;
+    }
+
+    // Make additional libraries in sphal to be accessible
+    auto sphalNamespace = android_get_exported_namespace("sphal");
+    if (!sphalNamespace) {
+        ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+              mSphalLibraries.c_str());
+        return false;
+    }
+
+    if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
+        ALOGE("Failed to link sphal namespace[%s]", dlerror());
+        return false;
+    }
+
+    return true;
+}
+
 android_namespace_t* GraphicsEnv::getDriverNamespace() {
-    static std::once_flag once;
-    std::call_once(once, [this]() {
-        if (mDriverPath.empty())
-            return;
-        // If the sphal namespace isn't configured for a device, don't support updatable drivers.
-        // We need a parent namespace to inherit the default search path from.
-        auto sphalNamespace = android_get_exported_namespace("sphal");
-        if (!sphalNamespace) return;
-        mDriverNamespace = android_create_namespace("gfx driver",
-                                                    nullptr,             // ld_library_path
-                                                    mDriverPath.c_str(), // default_library_path
-                                                    ANDROID_NAMESPACE_TYPE_SHARED |
-                                                            ANDROID_NAMESPACE_TYPE_ISOLATED,
-                                                    nullptr, // permitted_when_isolated_path
-                                                    sphalNamespace);
-    });
+    std::lock_guard<std::mutex> lock(mNamespaceMutex);
+
+    if (mDriverNamespace) {
+        return mDriverNamespace;
+    }
+
+    if (mDriverPath.empty()) {
+        return nullptr;
+    }
+
+    auto vndkNamespace = android_get_exported_namespace("vndk");
+    if (!vndkNamespace) {
+        return nullptr;
+    }
+
+    mDriverNamespace = android_create_namespace("gfx driver",
+                                                mDriverPath.c_str(), // ld_library_path
+                                                mDriverPath.c_str(), // default_library_path
+                                                ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                                nullptr, // permitted_when_isolated_path
+                                                nullptr);
+
+    if (!linkDriverNamespaceLocked(vndkNamespace)) {
+        mDriverNamespace = nullptr;
+    }
+
     return mDriverNamespace;
 }
 
-} // namespace android
+android_namespace_t* GraphicsEnv::getAngleNamespace() {
+    std::lock_guard<std::mutex> lock(mNamespaceMutex);
 
-extern "C" android_namespace_t* android_getDriverNamespace() {
-    return android::GraphicsEnv::getInstance().getDriverNamespace();
+    if (mAngleNamespace) {
+        return mAngleNamespace;
+    }
+
+    if (mAnglePath.empty()) {
+        ALOGV("mAnglePath is empty, not creating ANGLE namespace");
+        return nullptr;
+    }
+
+    mAngleNamespace = android_create_namespace("ANGLE",
+                                               nullptr,            // ld_library_path
+                                               mAnglePath.c_str(), // default_library_path
+                                               ANDROID_NAMESPACE_TYPE_SHARED |
+                                                       ANDROID_NAMESPACE_TYPE_ISOLATED,
+                                               nullptr, // permitted_when_isolated_path
+                                               nullptr);
+
+    ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
+
+    return mAngleNamespace;
 }
+
+} // namespace android
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
new file mode 100644
index 0000000..db16f3c
--- /dev/null
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GpuService"
+
+#include <graphicsenv/IGpuService.h>
+
+#include <binder/IResultReceiver.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class BpGpuService : public BpInterface<IGpuService> {
+public:
+    explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
+
+    virtual void setGpuStats(const std::string& driverPackageName,
+                             const std::string& driverVersionName, uint64_t driverVersionCode,
+                             int64_t driverBuildTime, const std::string& appPackageName,
+                             const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+                             bool isDriverLoaded, int64_t driverLoadingTime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+
+        data.writeUtf8AsUtf16(driverPackageName);
+        data.writeUtf8AsUtf16(driverVersionName);
+        data.writeUint64(driverVersionCode);
+        data.writeInt64(driverBuildTime);
+        data.writeUtf8AsUtf16(appPackageName);
+        data.writeInt32(vulkanVersion);
+        data.writeInt32(static_cast<int32_t>(driver));
+        data.writeBool(isDriverLoaded);
+        data.writeInt64(driverLoadingTime);
+
+        remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+        if (!outStats) return UNEXPECTED_NULL;
+
+        Parcel data, reply;
+        status_t status;
+
+        if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK)
+            return status;
+
+        if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_GLOBAL_INFO, data, &reply)) !=
+            OK)
+            return status;
+
+        int32_t result = 0;
+        if ((status = reply.readInt32(&result)) != OK) return status;
+        if (result != OK) return result;
+
+        outStats->clear();
+        return reply.readParcelableVector(outStats);
+    }
+
+    virtual status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const {
+        if (!outStats) return UNEXPECTED_NULL;
+
+        Parcel data, reply;
+        status_t status;
+
+        if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK) {
+            return status;
+        }
+
+        if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_APP_INFO, data, &reply)) !=
+            OK) {
+            return status;
+        }
+
+        int32_t result = 0;
+        if ((status = reply.readInt32(&result)) != OK) return status;
+        if (result != OK) return result;
+
+        outStats->clear();
+        return reply.readParcelableVector(outStats);
+    }
+
+    virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
+                                const GraphicsEnv::Stats stats, const uint64_t value) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+
+        data.writeUtf8AsUtf16(appPackageName);
+        data.writeUint64(driverVersionCode);
+        data.writeInt32(static_cast<int32_t>(stats));
+        data.writeUint64(value);
+
+        remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
+
+status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                  uint32_t flags) {
+    ALOGV("onTransact code[0x%X]", code);
+
+    status_t status;
+    switch (code) {
+        case SET_GPU_STATS: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::string driverPackageName;
+            if ((status = data.readUtf8FromUtf16(&driverPackageName)) != OK) return status;
+
+            std::string driverVersionName;
+            if ((status = data.readUtf8FromUtf16(&driverVersionName)) != OK) return status;
+
+            uint64_t driverVersionCode;
+            if ((status = data.readUint64(&driverVersionCode)) != OK) return status;
+
+            int64_t driverBuildTime;
+            if ((status = data.readInt64(&driverBuildTime)) != OK) return status;
+
+            std::string appPackageName;
+            if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
+
+            int32_t vulkanVersion;
+            if ((status = data.readInt32(&vulkanVersion)) != OK) return status;
+
+            int32_t driver;
+            if ((status = data.readInt32(&driver)) != OK) return status;
+
+            bool isDriverLoaded;
+            if ((status = data.readBool(&isDriverLoaded)) != OK) return status;
+
+            int64_t driverLoadingTime;
+            if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
+
+            setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
+                        appPackageName, vulkanVersion, static_cast<GraphicsEnv::Driver>(driver),
+                        isDriverLoaded, driverLoadingTime);
+
+            return OK;
+        }
+        case GET_GPU_STATS_GLOBAL_INFO: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::vector<GpuStatsGlobalInfo> stats;
+            const status_t result = getGpuStatsGlobalInfo(&stats);
+
+            if ((status = reply->writeInt32(result)) != OK) return status;
+            if (result != OK) return result;
+
+            if ((status = reply->writeParcelableVector(stats)) != OK) return status;
+
+            return OK;
+        }
+        case GET_GPU_STATS_APP_INFO: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::vector<GpuStatsAppInfo> stats;
+            const status_t result = getGpuStatsAppInfo(&stats);
+
+            if ((status = reply->writeInt32(result)) != OK) return status;
+            if (result != OK) return result;
+
+            if ((status = reply->writeParcelableVector(stats)) != OK) return status;
+
+            return OK;
+        }
+        case SET_TARGET_STATS: {
+            CHECK_INTERFACE(IGpuService, data, reply);
+
+            std::string appPackageName;
+            if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
+
+            uint64_t driverVersionCode;
+            if ((status = data.readUint64(&driverVersionCode)) != OK) return status;
+
+            int32_t stats;
+            if ((status = data.readInt32(&stats)) != OK) return status;
+
+            uint64_t value;
+            if ((status = data.readUint64(&value)) != OK) return status;
+
+            setTargetStats(appPackageName, driverVersionCode,
+                           static_cast<GraphicsEnv::Stats>(stats), value);
+
+            return OK;
+        }
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+
+            std::vector<String16> args;
+            data.readString16Vector(&args);
+
+            sp<IBinder> unusedCallback;
+            if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK) return status;
+
+            sp<IResultReceiver> resultReceiver;
+            if ((status = data.readNullableStrongBinder(&resultReceiver)) != OK) return status;
+
+            status = shellCommand(in, out, err, args);
+            if (resultReceiver != nullptr) resultReceiver->send(status);
+
+            return OK;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
new file mode 100644
index 0000000..edcccfe
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+/*
+ * class for transporting gpu global stats from GpuService to authorized
+ * recipents. This class is intended to be a data container.
+ */
+class GpuStatsGlobalInfo : public Parcelable {
+public:
+    GpuStatsGlobalInfo() = default;
+    GpuStatsGlobalInfo(const GpuStatsGlobalInfo&) = default;
+    virtual ~GpuStatsGlobalInfo() = default;
+    virtual status_t writeToParcel(Parcel* parcel) const;
+    virtual status_t readFromParcel(const Parcel* parcel);
+    std::string toString() const;
+
+    std::string driverPackageName = "";
+    std::string driverVersionName = "";
+    uint64_t driverVersionCode = 0;
+    int64_t driverBuildTime = 0;
+    int32_t glLoadingCount = 0;
+    int32_t glLoadingFailureCount = 0;
+    int32_t vkLoadingCount = 0;
+    int32_t vkLoadingFailureCount = 0;
+    int32_t vulkanVersion = 0;
+    int32_t cpuVulkanVersion = 0;
+    int32_t glesVersion = 0;
+    int32_t angleLoadingCount = 0;
+    int32_t angleLoadingFailureCount = 0;
+};
+
+/*
+ * class for transporting gpu app stats from GpuService to authorized recipents.
+ * This class is intended to be a data container.
+ */
+class GpuStatsAppInfo : public Parcelable {
+public:
+    GpuStatsAppInfo() = default;
+    GpuStatsAppInfo(const GpuStatsAppInfo&) = default;
+    virtual ~GpuStatsAppInfo() = default;
+    virtual status_t writeToParcel(Parcel* parcel) const;
+    virtual status_t readFromParcel(const Parcel* parcel);
+    std::string toString() const;
+
+    std::string appPackageName = "";
+    uint64_t driverVersionCode = 0;
+    std::vector<int64_t> glDriverLoadingTime = {};
+    std::vector<int64_t> vkDriverLoadingTime = {};
+    std::vector<int64_t> angleDriverLoadingTime = {};
+    bool cpuVulkanInUse = false;
+};
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 213580c..937bcd9 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -17,53 +17,143 @@
 #ifndef ANDROID_UI_GRAPHICS_ENV_H
 #define ANDROID_UI_GRAPHICS_ENV_H 1
 
+#include <mutex>
 #include <string>
+#include <vector>
 
 struct android_namespace_t;
 
 namespace android {
 
+struct NativeLoaderNamespace;
+
 class GraphicsEnv {
 public:
+    enum Api {
+        API_GL = 0,
+        API_VK = 1,
+    };
+
+    enum Driver {
+        NONE = 0,
+        GL = 1,
+        GL_UPDATED = 2,
+        VULKAN = 3,
+        VULKAN_UPDATED = 4,
+        ANGLE = 5,
+    };
+
+    enum Stats {
+        CPU_VULKAN_IN_USE = 0,
+    };
+
+private:
+    struct GpuStats {
+        std::string driverPackageName;
+        std::string driverVersionName;
+        uint64_t driverVersionCode;
+        int64_t driverBuildTime;
+        std::string appPackageName;
+        int32_t vulkanVersion;
+        Driver glDriverToLoad;
+        Driver glDriverFallback;
+        Driver vkDriverToLoad;
+        Driver vkDriverFallback;
+        bool glDriverToSend;
+        bool vkDriverToSend;
+        int64_t glDriverLoadingTime;
+        int64_t vkDriverLoadingTime;
+
+        GpuStats()
+              : driverPackageName(""),
+                driverVersionName(""),
+                driverVersionCode(0),
+                driverBuildTime(0),
+                appPackageName(""),
+                vulkanVersion(0),
+                glDriverToLoad(Driver::NONE),
+                glDriverFallback(Driver::NONE),
+                vkDriverToLoad(Driver::NONE),
+                vkDriverFallback(Driver::NONE),
+                glDriverToSend(false),
+                vkDriverToSend(false),
+                glDriverLoadingTime(0),
+                vkDriverLoadingTime(0) {}
+    };
+
+public:
     static GraphicsEnv& getInstance();
 
+    int getCanLoadSystemLibraries();
+
     // Set a search path for loading graphics drivers. The path is a list of
     // directories separated by ':'. A directory can be contained in a zip file
     // (drivers must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /data/app/com.example.driver/base.apk!/lib/arm64-v8a
-    void setDriverPath(const std::string path);
+    // Also set additional required sphal libraries to the linker for loading
+    // graphics drivers. The string is a list of libraries separated by ':',
+    // which is required by android_link_namespaces.
+    void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
     android_namespace_t* getDriverNamespace();
+    void hintActivityLaunch();
+    void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
+                     uint64_t versionCode, int64_t driverBuildTime,
+                     const std::string& appPackageName, const int32_t vulkanVersion);
+    void setTargetStats(const Stats stats, const uint64_t value = 0);
+    void setDriverToLoad(Driver driver);
+    void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
+    void sendGpuStatsLocked(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
 
-    void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths);
-    android_namespace_t* getAppNamespace();
-    const std::string getLayerPaths();
+    bool shouldUseAngle(std::string appName);
+    bool shouldUseAngle();
+    // Set a search path for loading ANGLE libraries. The path is a list of
+    // directories separated by ':'. A directory can be contained in a zip file
+    // (libraries must be stored uncompressed and page aligned); such elements
+    // in the search path must have a '!' after the zip filename, e.g.
+    //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
+    void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
+                      const int rulesFd, const long rulesOffset, const long rulesLength);
+    android_namespace_t* getAngleNamespace();
+    std::string& getAngleAppName();
+
+    void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
+    NativeLoaderNamespace* getAppNamespace();
+
+    const std::string& getLayerPaths();
 
     void setDebugLayers(const std::string layers);
-    const std::string getDebugLayers();
+    void setDebugLayersGLES(const std::string layers);
+    const std::string& getDebugLayers();
+    const std::string& getDebugLayersGLES();
 
 private:
+    enum UseAngle { UNKNOWN, YES, NO };
+
+    void* loadLibrary(std::string name);
+    bool checkAngleRules(void* so);
+    void updateUseAngle();
+    bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
+
     GraphicsEnv() = default;
     std::string mDriverPath;
+    std::string mSphalLibraries;
+    std::mutex mStatsLock;
+    GpuStats mGpuStats;
+    std::string mAnglePath;
+    std::string mAngleAppName;
+    std::string mAngleDeveloperOptIn;
+    std::vector<char> mRulesBuffer;
+    UseAngle mUseAngle = UNKNOWN;
     std::string mDebugLayers;
+    std::string mDebugLayersGLES;
     std::string mLayerPaths;
+    std::mutex mNamespaceMutex;
     android_namespace_t* mDriverNamespace = nullptr;
-    android_namespace_t* mAppNamespace = nullptr;
+    android_namespace_t* mAngleNamespace = nullptr;
+    NativeLoaderNamespace* mAppNamespace = nullptr;
 };
 
 } // namespace android
 
-/* FIXME
- * Export an un-mangled function that just does
- *     return android::GraphicsEnv::getInstance().getDriverNamespace();
- * This allows libEGL to get the function pointer via dlsym, since it can't
- * directly link against libgui. In a future release, we'll fix this so that
- * libgui does not depend on graphics API libraries, and libEGL can link
- * against it. The current dependencies from libgui -> libEGL are:
- *  - the GLConsumer class, which should be moved to its own library
- *  - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
- *    will be removed soon.
- */
-extern "C" android_namespace_t* android_getDriverNamespace();
-
 #endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
new file mode 100644
index 0000000..b8d0bd1
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
+#include <graphicsenv/GraphicsEnv.h>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for GPU-related queries and
+ * control.
+ */
+class IGpuService : public IInterface {
+public:
+    DECLARE_META_INTERFACE(GpuService)
+
+    // set GPU stats from GraphicsEnvironment.
+    virtual void setGpuStats(const std::string& driverPackageName,
+                             const std::string& driverVersionName, uint64_t driverVersionCode,
+                             int64_t driverBuildTime, const std::string& appPackageName,
+                             const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+                             bool isDriverLoaded, int64_t driverLoadingTime) = 0;
+
+    // set target stats.
+    virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
+                                const GraphicsEnv::Stats stats, const uint64_t value = 0) = 0;
+
+    // get GPU global stats from GpuStats module.
+    virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
+
+    // get GPU app stats from GpuStats module.
+    virtual status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const = 0;
+};
+
+class BnGpuService : public BnInterface<IGpuService> {
+public:
+    enum IGpuServiceTag {
+        SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
+        GET_GPU_STATS_GLOBAL_INFO,
+        GET_GPU_STATS_APP_INFO,
+        SET_TARGET_STATS,
+        // Always append new enum to the end.
+    };
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+
+protected:
+    virtual status_t shellCommand(int in, int out, int err, std::vector<String16>& args) = 0;
+};
+
+} // namespace android
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 73f2147..34575f5 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -23,58 +23,100 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
+
+    defaults: ["libgui_bufferqueue-defaults"],
+
+    srcs: [
+        "BitTube.cpp",
+        "BufferHubConsumer.cpp",
+        "BufferHubProducer.cpp",
+        "BufferItemConsumer.cpp",
+        "ConsumerBase.cpp",
+        "CpuConsumer.cpp",
+        "DisplayEventReceiver.cpp",
+        "GLConsumer.cpp",
+        "GuiConfig.cpp",
+        "IDisplayEventConnection.cpp",
+        "IRegionSamplingListener.cpp",
+        "ISurfaceComposer.cpp",
+        "ISurfaceComposerClient.cpp",
+        "ITransactionCompletedListener.cpp",
+        "LayerDebugInfo.cpp",
+        "LayerMetadata.cpp",
+        "LayerState.cpp",
+        "StreamSplitter.cpp",
+        "Surface.cpp",
+        "SurfaceControl.cpp",
+        "SurfaceComposerClient.cpp",
+        "SyncFeatures.cpp",
+        "view/Surface.cpp",
+    ],
+
+    shared_libs: [
+        "android.frameworks.bufferhub@1.0",
+        "libbufferhub",
+        "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+        "libinput",
+        "libpdx_default_transport",
+    ],
+
+    // bufferhub is not used when building libgui for vendors
+    target: {
+        vendor: {
+            cflags: [
+                "-DNO_BUFFERHUB",
+                "-DNO_INPUT",
+            ],
+            exclude_srcs: [
+                "BufferHubConsumer.cpp",
+                "BufferHubProducer.cpp",
+            ],
+            exclude_shared_libs: [
+                "android.frameworks.bufferhub@1.0",
+                "libbufferhub",
+                "libbufferhubqueue",
+                "libinput",
+                "libpdx_default_transport",
+            ],
+        },
+    },
+
+    header_libs: [
+        "libdvr_headers",
+        "libpdx_headers",
+    ],
+}
+
+// Used by media codec services exclusively as a static lib for
+// core bufferqueue support only.
+cc_library_static {
+    name: "libgui_bufferqueue_static",
+    vendor_available: true,
+
+    cflags: [
+        "-DNO_BUFFERHUB",
+    ],
+
+    defaults: ["libgui_bufferqueue-defaults"],
+}
+
+// Common build config shared by libgui and libgui_bufferqueue_static.
+cc_defaults {
+    name: "libgui_bufferqueue-defaults",
 
     clang: true,
     cflags: [
         "-Wall",
         "-Werror",
     ],
+
     cppflags: [
-        "-Weverything",
-
-        // The static constructors and destructors in this library have not been noted to
-        // introduce significant overheads
-        "-Wno-exit-time-destructors",
-        "-Wno-global-constructors",
-
-        // We only care about compiling as C++14
-        "-Wno-c++98-compat-pedantic",
-
-        // We don't need to enumerate every case in a switch as long as a default case
-        // is present
-        "-Wno-switch-enum",
-
-        // Allow calling variadic macros without a __VA_ARGS__ list
-        "-Wno-gnu-zero-variadic-macro-arguments",
-
-        // Don't warn about struct padding
-        "-Wno-padded",
-
-        // We are aware of the risks inherent in comparing floats for equality
-        "-Wno-float-equal",
-
-        // Pure abstract classes trigger this warning
-        "-Wno-weak-vtables",
-
-        // Allow four-character integer literals
-	"-Wno-four-char-constants",
-
-        // Allow documentation warnings
-        "-Wno-documentation",
-
-        // Allow implicit instantiation for templated class function
-        "-Wno-undefined-func-template",
-
-        // Allow explicitly marking struct as packed even when unnecessary
-        "-Wno-packed",
-
+        "-Wextra",
         "-DDEBUG_ONLY_CODE=0",
     ],
 
     product_variables: {
-        brillo: {
-            cflags: ["-DHAVE_NO_SURFACE_FLINGER"],
-        },
         eng: {
             cppflags: [
                 "-UDEBUG_ONLY_CODE",
@@ -84,84 +126,58 @@
     },
 
     srcs: [
-        "BitTube.cpp",
-        "BufferHubConsumer.cpp",
-        "BufferHubProducer.cpp",
         "BufferItem.cpp",
-        "BufferItemConsumer.cpp",
         "BufferQueue.cpp",
         "BufferQueueConsumer.cpp",
         "BufferQueueCore.cpp",
         "BufferQueueProducer.cpp",
+        "BufferQueueThreadState.cpp",
         "BufferSlot.cpp",
-        "ConsumerBase.cpp",
-        "CpuConsumer.cpp",
-        "DisplayEventReceiver.cpp",
         "FrameTimestamps.cpp",
-        "GLConsumer.cpp",
-        "GuiConfig.cpp",
+        "GLConsumerUtils.cpp",
         "HdrMetadata.cpp",
-        "IDisplayEventConnection.cpp",
         "IConsumerListener.cpp",
         "IGraphicBufferConsumer.cpp",
         "IGraphicBufferProducer.cpp",
         "IProducerListener.cpp",
-        "ISurfaceComposer.cpp",
-        "ISurfaceComposerClient.cpp",
-        "LayerDebugInfo.cpp",
-        "LayerState.cpp",
         "OccupancyTracker.cpp",
-        "StreamSplitter.cpp",
-        "Surface.cpp",
-        "SurfaceControl.cpp",
-        "SurfaceComposerClient.cpp",
-        "SyncFeatures.cpp",
-        "view/Surface.cpp",
         "bufferqueue/1.0/B2HProducerListener.cpp",
-        "bufferqueue/1.0/H2BGraphicBufferProducer.cpp"
+        "bufferqueue/1.0/Conversion.cpp",
+        "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
+        "bufferqueue/1.0/H2BProducerListener.cpp",
+        "bufferqueue/1.0/WProducerListener.cpp",
+        "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
+        "bufferqueue/2.0/B2HProducerListener.cpp",
+        "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
+        "bufferqueue/2.0/H2BProducerListener.cpp",
+        "bufferqueue/2.0/types.cpp",
     ],
 
     shared_libs: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.1",
-        "libsync",
+        "android.hardware.graphics.common@1.2",
+        "android.hidl.token@1.0-utils",
+        "libbase",
         "libbinder",
-        "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
-        "libpdx_default_transport",
         "libcutils",
         "libEGL",
         "libGLESv2",
-        "libui",
-        "libutils",
-        "libnativewindow",
-        "liblog",
         "libhidlbase",
         "libhidltransport",
-        "android.hidl.token@1.0-utils",
-        "android.hardware.graphics.bufferqueue@1.0",
-        "android.hardware.configstore@1.0",
-        "android.hardware.configstore-utils",
+        "libhwbinder",
+        "liblog",
+        "libnativewindow",
+        "libsync",
+        "libui",
+        "libutils",
+        "libvndksupport",
     ],
 
-    // bufferhub is not used when building libgui for vendors
-    target: {
-        vendor: {
-            cflags: ["-DNO_BUFFERHUB"],
-            exclude_srcs: [
-                "BufferHubConsumer.cpp",
-                "BufferHubProducer.cpp",
-            ],
-            exclude_shared_libs: [
-                "libbufferhubqueue",
-                "libpdx_default_transport",
-            ],
-        },
-    },
-
     header_libs: [
-        "libdvr_headers",
-        "libnativebase_headers",
         "libgui_headers",
-        "libpdx_headers",
+        "libnativebase_headers",
     ],
 
     export_shared_lib_headers: [
@@ -169,9 +185,11 @@
         "libEGL",
         "libnativewindow",
         "libui",
-        "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hidl.token@1.0-utils",
     ],
 
     export_header_lib_headers: [
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index ae5cca2..4be014f 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <log/log.h>
 #include <system/window.h>
+#include <ui/BufferHubBuffer.h>
 
 namespace android {
 
@@ -63,13 +64,13 @@
     } else if (buffers_[slot].mGraphicBuffer != nullptr) {
         ALOGE("requestBuffer: slot %d is not empty.", slot);
         return BAD_VALUE;
-    } else if (buffers_[slot].mBufferProducer == nullptr) {
+    } else if (buffers_[slot].mProducerBuffer == nullptr) {
         ALOGE("requestBuffer: slot %d is not dequeued.", slot);
         return BAD_VALUE;
     }
 
-    const auto& buffer_producer = buffers_[slot].mBufferProducer;
-    sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+    const auto& producer_buffer = buffers_[slot].mProducerBuffer;
+    sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
 
     buffers_[slot].mGraphicBuffer = graphic_buffer;
     buffers_[slot].mRequestBufferCalled = true;
@@ -157,19 +158,19 @@
     }
 
     size_t slot = 0;
-    std::shared_ptr<BufferProducer> buffer_producer;
+    std::shared_ptr<ProducerBuffer> producer_buffer;
 
     for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
         LocalHandle fence;
         auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
         if (!buffer_status) return NO_MEMORY;
 
-        buffer_producer = buffer_status.take();
-        if (!buffer_producer) return NO_MEMORY;
+        producer_buffer = buffer_status.take();
+        if (!producer_buffer) return NO_MEMORY;
 
-        if (width == buffer_producer->width() && height == buffer_producer->height() &&
-            uint32_t(format) == buffer_producer->format()) {
-            // The producer queue returns a buffer producer matches the request.
+        if (width == producer_buffer->width() && height == producer_buffer->height() &&
+            uint32_t(format) == producer_buffer->format()) {
+            // The producer queue returns a producer buffer matches the request.
             break;
         }
 
@@ -178,8 +179,8 @@
         ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
               "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
               "re-allocattion.",
-              width, height, format, slot, buffer_producer->width(), buffer_producer->height(),
-              buffer_producer->format());
+              width, height, format, slot, producer_buffer->width(), producer_buffer->height(),
+              producer_buffer->format());
         // Mark the slot as reallocating, so that later we can set
         // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
         buffers_[slot].mIsReallocating = true;
@@ -224,23 +225,172 @@
     return ret;
 }
 
-status_t BufferHubProducer::detachBuffer(int /* slot */) {
-    ALOGE("BufferHubProducer::detachBuffer not implemented.");
+status_t BufferHubProducer::detachBuffer(int slot) {
+    ALOGV("detachBuffer: slot=%d", slot);
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    return DetachBufferLocked(static_cast<size_t>(slot));
+}
+
+status_t BufferHubProducer::DetachBufferLocked(size_t slot) {
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("detachBuffer: BufferHubProducer is not connected.");
+        return NO_INIT;
+    }
+
+    if (slot >= static_cast<size_t>(max_buffer_count_)) {
+        ALOGE("detachBuffer: slot index %zu out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("detachBuffer: slot %zu is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mRequestBufferCalled) {
+        ALOGE("detachBuffer: buffer in slot %zu has not been requested", slot);
+        return BAD_VALUE;
+    }
+    std::shared_ptr<ProducerBuffer> producer_buffer = queue_->GetBuffer(slot);
+    if (producer_buffer == nullptr || producer_buffer->buffer() == nullptr) {
+        ALOGE("detachBuffer: Invalid ProducerBuffer at slot %zu.", slot);
+        return BAD_VALUE;
+    }
+    sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
+    if (graphic_buffer == nullptr) {
+        ALOGE("detachBuffer: Invalid GraphicBuffer at slot %zu.", slot);
+        return BAD_VALUE;
+    }
+
+    // Remove the ProducerBuffer from the ProducerQueue.
+    status_t error = RemoveBuffer(slot);
+    if (error != NO_ERROR) {
+        ALOGE("detachBuffer: Failed to remove buffer, slot=%zu, error=%d.", slot, error);
+        return error;
+    }
+
+    // Here we need to convert the existing ProducerBuffer into a DetachedBufferHandle and inject
+    // the handle into the GraphicBuffer object at the requested slot.
+    auto status_or_handle = producer_buffer->Detach();
+    if (!status_or_handle.ok()) {
+        ALOGE("detachBuffer: Failed to detach from a ProducerBuffer at slot %zu, error=%d.", slot,
+              status_or_handle.error());
+        return BAD_VALUE;
+    }
+
+    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+    // be directly backed by BufferHub.
     return INVALID_OPERATION;
 }
 
-status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */,
-                                             sp<Fence>* /* out_fence */) {
-    ALOGE("BufferHubProducer::detachNextBuffer not implemented.");
-    return INVALID_OPERATION;
+status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
+    ALOGV("detachNextBuffer.");
+
+    if (out_buffer == nullptr || out_fence == nullptr) {
+        ALOGE("detachNextBuffer: Invalid parameter: out_buffer=%p, out_fence=%p", out_buffer,
+              out_fence);
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("detachNextBuffer: BufferHubProducer is not connected.");
+        return NO_INIT;
+    }
+
+    // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, and detachBuffer in
+    // sequence, except for two things:
+    //
+    // 1) It is unnecessary to know the dimensions, format, or usage of the next buffer, i.e. the
+    // function just returns whatever ProducerBuffer is available from the ProducerQueue and no
+    // buffer allocation or re-allocation will happen.
+    // 2) It will not block, since if it cannot find an appropriate buffer to return, it will return
+    // an error instead.
+    size_t slot = 0;
+    LocalHandle fence;
+
+    // First, dequeue a ProducerBuffer from the ProducerQueue with no timeout. Report error
+    // immediately if ProducerQueue::Dequeue() fails.
+    auto status_or_buffer = queue_->Dequeue(/*timeout=*/0, &slot, &fence);
+    if (!status_or_buffer.ok()) {
+        ALOGE("detachNextBuffer: Failed to dequeue buffer, error=%d.", status_or_buffer.error());
+        return NO_MEMORY;
+    }
+
+    std::shared_ptr<ProducerBuffer> producer_buffer = status_or_buffer.take();
+    if (producer_buffer == nullptr) {
+        ALOGE("detachNextBuffer: Dequeued buffer is null.");
+        return NO_MEMORY;
+    }
+
+    // With the BufferHub backed solution, slot returned from |queue_->Dequeue| is guaranteed to
+    // be available for producer's use. It's either in free state (if the buffer has never been used
+    // before) or in queued state (if the buffer has been dequeued and queued back to
+    // BufferHubQueue).
+    if (!buffers_[slot].mBufferState.isFree() && !buffers_[slot].mBufferState.isQueued()) {
+        ALOGE("detachNextBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    }
+    if (buffers_[slot].mProducerBuffer == nullptr) {
+        ALOGE("detachNextBuffer: ProducerBuffer at slot %zu is null.", slot);
+        return BAD_VALUE;
+    }
+    if (buffers_[slot].mProducerBuffer->id() != producer_buffer->id()) {
+        ALOGE("detachNextBuffer: ProducerBuffer at slot %zu has mismatched id, actual: "
+              "%d, expected: %d.",
+              slot, buffers_[slot].mProducerBuffer->id(), producer_buffer->id());
+        return BAD_VALUE;
+    }
+
+    ALOGV("detachNextBuffer: slot=%zu", slot);
+    buffers_[slot].mBufferState.freeQueued();
+    buffers_[slot].mBufferState.dequeue();
+
+    // Second, request the buffer.
+    sp<GraphicBuffer> graphic_buffer = producer_buffer->buffer()->buffer();
+    buffers_[slot].mGraphicBuffer = producer_buffer->buffer()->buffer();
+
+    // Finally, detach the buffer and then return.
+    status_t error = DetachBufferLocked(slot);
+    if (error == NO_ERROR) {
+        *out_fence = new Fence(fence.Release());
+        *out_buffer = graphic_buffer;
+    }
+    return error;
 }
 
-status_t BufferHubProducer::attachBuffer(int* /* out_slot */,
-                                         const sp<GraphicBuffer>& /* buffer */) {
-    // With this BufferHub backed implementation, we assume (for now) all buffers
-    // are allocated and owned by the BufferHub. Thus the attempt of transfering
-    // ownership of a buffer to the buffer queue is intentionally unsupported.
-    LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported.");
+status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) {
+    // In the BufferHub design, all buffers are allocated and owned by the BufferHub. Thus only
+    // GraphicBuffers that are originated from BufferHub can be attached to a BufferHubProducer.
+    ALOGV("queueBuffer: buffer=%p", buffer.get());
+
+    if (out_slot == nullptr) {
+        ALOGE("attachBuffer: out_slot cannot be NULL.");
+        return BAD_VALUE;
+    }
+    if (buffer == nullptr) {
+        ALOGE("attachBuffer: invalid GraphicBuffer.");
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("attachBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    // Before attaching the buffer, caller is supposed to call
+    // IGraphicBufferProducer::setGenerationNumber to inform the
+    // BufferHubProducer the next generation number.
+    if (buffer->getGenerationNumber() != generation_number_) {
+        ALOGE("attachBuffer: Mismatched generation number, buffer: %u, queue: %u.",
+              buffer->getGenerationNumber(), generation_number_);
+        return BAD_VALUE;
+    }
+
+    // TODO(b/70912269): Reimplement BufferHubProducer::DetachBufferLocked() once GraphicBuffer can
+    // be directly backed by BufferHub.
     return INVALID_OPERATION;
 }
 
@@ -302,11 +452,11 @@
         return BAD_VALUE;
     }
 
-    // Post the buffer producer with timestamp in the metadata.
-    const auto& buffer_producer = buffers_[slot].mBufferProducer;
+    // Post the producer buffer with timestamp in the metadata.
+    const auto& producer_buffer = buffers_[slot].mProducerBuffer;
 
     // Check input crop is not out of boundary of current buffer.
-    Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
+    Rect buffer_rect(producer_buffer->width(), producer_buffer->height());
     Rect cropped_rect(Rect::EMPTY_RECT);
     crop.intersect(buffer_rect, &cropped_rect);
     if (cropped_rect != crop) {
@@ -327,11 +477,11 @@
     meta_data.scaling_mode = int32_t(scaling_mode);
     meta_data.transform = int32_t(transform);
 
-    buffer_producer->PostAsync(&meta_data, fence_fd);
+    producer_buffer->PostAsync(&meta_data, fence_fd);
     buffers_[slot].mBufferState.queue();
 
-    output->width = buffer_producer->width();
-    output->height = buffer_producer->height();
+    output->width = producer_buffer->width();
+    output->height = producer_buffer->height();
     output->transformHint = 0; // default value, we don't use it yet.
 
     // |numPendingBuffers| counts of the number of buffers that has been enqueued
@@ -369,8 +519,8 @@
         return BAD_VALUE;
     }
 
-    auto buffer_producer = buffers_[slot].mBufferProducer;
-    queue_->Enqueue(buffer_producer, size_t(slot), 0ULL);
+    auto producer_buffer = buffers_[slot].mProducerBuffer;
+    queue_->Enqueue(producer_buffer, size_t(slot), 0U);
     buffers_[slot].mBufferState.cancel();
     buffers_[slot].mFence = fence;
     ALOGV("cancelBuffer: slot %d", slot);
@@ -641,12 +791,12 @@
     }
 
     size_t slot = status.get();
-    auto buffer_producer = queue_->GetBuffer(slot);
+    auto producer_buffer = queue_->GetBuffer(slot);
 
-    LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu",
-                        slot);
+    LOG_ALWAYS_FATAL_IF(producer_buffer == nullptr,
+                        "Failed to get the producer buffer at slot: %zu", slot);
 
-    buffers_[slot].mBufferProducer = buffer_producer;
+    buffers_[slot].mProducerBuffer = producer_buffer;
 
     return NO_ERROR;
 }
@@ -654,26 +804,28 @@
 status_t BufferHubProducer::RemoveBuffer(size_t slot) {
     auto status = queue_->RemoveBuffer(slot);
     if (!status) {
-        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s",
-              status.GetErrorMessage().c_str());
+        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer at slot: %zu, error: %s.",
+              slot, status.GetErrorMessage().c_str());
         return INVALID_OPERATION;
     }
 
     // Reset in memory objects related the the buffer.
-    buffers_[slot].mBufferProducer = nullptr;
-    buffers_[slot].mGraphicBuffer = nullptr;
+    buffers_[slot].mProducerBuffer = nullptr;
     buffers_[slot].mBufferState.detachProducer();
+    buffers_[slot].mFence = Fence::NO_FENCE;
+    buffers_[slot].mGraphicBuffer = nullptr;
+    buffers_[slot].mRequestBufferCalled = false;
     return NO_ERROR;
 }
 
 status_t BufferHubProducer::FreeAllBuffers() {
     for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
         // Reset in memory objects related the the buffer.
-        buffers_[slot].mGraphicBuffer = nullptr;
+        buffers_[slot].mProducerBuffer = nullptr;
         buffers_[slot].mBufferState.reset();
-        buffers_[slot].mRequestBufferCalled = false;
-        buffers_[slot].mBufferProducer = nullptr;
         buffers_[slot].mFence = Fence::NO_FENCE;
+        buffers_[slot].mGraphicBuffer = nullptr;
+        buffers_[slot].mRequestBufferCalled = false;
     }
 
     auto status = queue_->FreeAllBuffers();
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index f50379b..5beba02 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -39,8 +39,8 @@
 }
 
 BufferItem::BufferItem() :
-    mGraphicBuffer(NULL),
-    mFence(NULL),
+    mGraphicBuffer(nullptr),
+    mFence(nullptr),
     mCrop(Rect::INVALID_RECT),
     mTransform(0),
     mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -91,11 +91,11 @@
 
 size_t BufferItem::getFlattenedSize() const {
     size_t size = sizeof(uint32_t); // Flags
-    if (mGraphicBuffer != 0) {
+    if (mGraphicBuffer != nullptr) {
         size += mGraphicBuffer->getFlattenedSize();
         size = FlattenableUtils::align<4>(size);
     }
-    if (mFence != 0) {
+    if (mFence != nullptr) {
         size += mFence->getFlattenedSize();
         size = FlattenableUtils::align<4>(size);
     }
@@ -107,10 +107,10 @@
 
 size_t BufferItem::getFdCount() const {
     size_t count = 0;
-    if (mGraphicBuffer != 0) {
+    if (mGraphicBuffer != nullptr) {
         count += mGraphicBuffer->getFdCount();
     }
-    if (mFence != 0) {
+    if (mFence != nullptr) {
         count += mFence->getFdCount();
     }
     return count;
@@ -137,13 +137,13 @@
     FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
 
     flags = 0;
-    if (mGraphicBuffer != 0) {
+    if (mGraphicBuffer != nullptr) {
         status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
         flags |= 1;
     }
-    if (mFence != 0) {
+    if (mFence != nullptr) {
         status_t err = mFence->flatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 89bc0c4..f50bc20 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -107,7 +107,7 @@
 
 void BufferItemConsumer::freeBufferLocked(int slotIndex) {
     sp<BufferFreedListener> listener = mBufferFreedListener.promote();
-    if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) {
+    if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) {
         // Fire callback if we have a listener registered and the buffer being freed is valid.
         BI_LOGV("actually calling onBufferFreed");
         listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index a8da134..5fb3f0b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -38,7 +38,7 @@
 
 void BufferQueue::ProxyConsumerListener::onDisconnect() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onDisconnect();
     }
 }
@@ -46,7 +46,7 @@
 void BufferQueue::ProxyConsumerListener::onFrameAvailable(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onFrameAvailable(item);
     }
 }
@@ -54,21 +54,21 @@
 void BufferQueue::ProxyConsumerListener::onFrameReplaced(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onFrameReplaced(item);
     }
 }
 
 void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 }
 
 void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onSidebandStreamChanged();
     }
 }
@@ -85,21 +85,21 @@
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
         sp<IGraphicBufferConsumer>* outConsumer,
         bool consumerIsSurfaceFlinger) {
-    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+    LOG_ALWAYS_FATAL_IF(outProducer == nullptr,
             "BufferQueue: outProducer must not be NULL");
-    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,
             "BufferQueue: outConsumer must not be NULL");
 
     sp<BufferQueueCore> core(new BufferQueueCore());
-    LOG_ALWAYS_FATAL_IF(core == NULL,
+    LOG_ALWAYS_FATAL_IF(core == nullptr,
             "BufferQueue: failed to create BufferQueueCore");
 
     sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
-    LOG_ALWAYS_FATAL_IF(producer == NULL,
+    LOG_ALWAYS_FATAL_IF(producer == nullptr,
             "BufferQueue: failed to create BufferQueueProducer");
 
     sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
-    LOG_ALWAYS_FATAL_IF(consumer == NULL,
+    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
             "BufferQueue: failed to create BufferQueueConsumer");
 
     *outProducer = producer;
@@ -109,8 +109,8 @@
 #ifndef NO_BUFFERHUB
 void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
                                        sp<IGraphicBufferConsumer>* outConsumer) {
-    LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL");
-    LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BufferQueue: outConsumer must not be NULL");
 
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
@@ -118,16 +118,16 @@
     dvr::ProducerQueueConfigBuilder configBuilder;
     std::shared_ptr<dvr::ProducerQueue> producerQueue =
             dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
-    LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue.");
+    LOG_ALWAYS_FATAL_IF(producerQueue == nullptr, "BufferQueue: failed to create ProducerQueue.");
 
     std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
-    LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue.");
+    LOG_ALWAYS_FATAL_IF(consumerQueue == nullptr, "BufferQueue: failed to create ConsumerQueue.");
 
     producer = BufferHubProducer::Create(producerQueue);
     consumer = BufferHubConsumer::Create(consumerQueue);
 
-    LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer");
-    LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer");
+    LOG_ALWAYS_FATAL_IF(producer == nullptr, "BufferQueue: failed to create BufferQueueProducer");
+    LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BufferQueue: failed to create BufferQueueConsumer");
 
     *outProducer = producer;
     *outConsumer = consumer;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d70e142..528bfb1 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -34,9 +34,10 @@
 #include <gui/IConsumerListener.h>
 #include <gui/IProducerListener.h>
 
-#include <binder/IPCThreadState.h>
+#include <private/gui/BufferQueueThreadState.h>
 #ifndef __ANDROID_VNDK__
 #include <binder/PermissionCache.h>
+#include <vndksupport/linker.h>
 #endif
 
 #include <system/window.h>
@@ -57,7 +58,7 @@
     int numDroppedBuffers = 0;
     sp<IProducerListener> listener;
     {
-        Mutex::Autolock lock(mCore->mMutex);
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
 
         // Check that the consumer doesn't currently have the maximum number of
         // buffers acquired. We allow the max buffer count to be exceeded by one
@@ -93,8 +94,6 @@
         // Skip this if we're in shared buffer mode and the queue is empty,
         // since in that case we'll just return the shared buffer.
         if (expectedPresent != 0 && !mCore->mQueue.empty()) {
-            const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
-
             // The 'expectedPresent' argument indicates when the buffer is expected
             // to be presented on-screen. If the buffer's desired present time is
             // earlier (less) than expectedPresent -- meaning it will be displayed
@@ -189,6 +188,7 @@
                         desiredPresent - expectedPresent,
                         systemTime(CLOCK_MONOTONIC),
                         front->mFrameNumber, maxFrameNumber);
+                ATRACE_NAME("PRESENT_LATER");
                 return PRESENT_LATER;
             }
 
@@ -202,7 +202,7 @@
 
         if (sharedBufferAvailable && mCore->mQueue.empty()) {
             // make sure the buffer has finished allocating before acquiring it
-            mCore->waitWhileAllocatingLocked();
+            mCore->waitWhileAllocatingLocked(lock);
 
             slot = mCore->mSharedBufferSlot;
 
@@ -255,7 +255,7 @@
         // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
         // on the consumer side
         if (outBuffer->mAcquireCalled) {
-            outBuffer->mGraphicBuffer = NULL;
+            outBuffer->mGraphicBuffer = nullptr;
         }
 
         mCore->mQueue.erase(front);
@@ -263,7 +263,7 @@
         // We might have freed a slot while dropping old buffers, or the producer
         // may be blocked waiting for the number of buffers in the queue to
         // decrease.
-        mCore->mDequeueCondition.broadcast();
+        mCore->mDequeueCondition.notify_all();
 
         ATRACE_INT(mCore->mConsumerName.string(),
                 static_cast<int32_t>(mCore->mQueue.size()));
@@ -272,7 +272,7 @@
         VALIDATE_CONSISTENCY();
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         for (int i = 0; i < numDroppedBuffers; ++i) {
             listener->onBufferReleased();
         }
@@ -285,7 +285,7 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
@@ -311,7 +311,7 @@
     mCore->mActiveBuffers.erase(slot);
     mCore->mFreeSlots.insert(slot);
     mCore->clearBufferSlotLocked(slot);
-    mCore->mDequeueCondition.broadcast();
+    mCore->mDequeueCondition.notify_all();
     VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
@@ -321,15 +321,15 @@
         const sp<android::GraphicBuffer>& buffer) {
     ATRACE_CALL();
 
-    if (outSlot == NULL) {
+    if (outSlot == nullptr) {
         BQ_LOGE("attachBuffer: outSlot must not be NULL");
         return BAD_VALUE;
-    } else if (buffer == NULL) {
+    } else if (buffer == nullptr) {
         BQ_LOGE("attachBuffer: cannot attach NULL buffer");
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mSharedBufferMode) {
         BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
@@ -413,7 +413,7 @@
     ATRACE_BUFFER_INDEX(slot);
 
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
-            releaseFence == NULL) {
+            releaseFence == nullptr) {
         BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
                 releaseFence.get());
         return BAD_VALUE;
@@ -421,7 +421,7 @@
 
     sp<IProducerListener> listener;
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
 
         // If the frame number has changed because the buffer has been reallocated,
         // we can ignore this releaseBuffer for the old buffer.
@@ -460,12 +460,12 @@
         listener = mCore->mConnectedProducerListener;
         BQ_LOGV("releaseBuffer: releasing slot %d", slot);
 
-        mCore->mDequeueCondition.broadcast();
+        mCore->mDequeueCondition.notify_all();
         VALIDATE_CONSISTENCY();
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBufferReleased();
     }
 
@@ -476,7 +476,7 @@
         const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
     ATRACE_CALL();
 
-    if (consumerListener == NULL) {
+    if (consumerListener == nullptr) {
         BQ_LOGE("connect: consumerListener may not be NULL");
         return BAD_VALUE;
     }
@@ -484,7 +484,7 @@
     BQ_LOGV("connect: controlledByApp=%s",
             controlledByApp ? "true" : "false");
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("connect: BufferQueue has been abandoned");
@@ -502,31 +502,31 @@
 
     BQ_LOGV("disconnect");
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
-    if (mCore->mConsumerListener == NULL) {
+    if (mCore->mConsumerListener == nullptr) {
         BQ_LOGE("disconnect: no consumer is connected");
         return BAD_VALUE;
     }
 
     mCore->mIsAbandoned = true;
-    mCore->mConsumerListener = NULL;
+    mCore->mConsumerListener = nullptr;
     mCore->mQueue.clear();
     mCore->freeAllBuffersLocked();
     mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
-    mCore->mDequeueCondition.broadcast();
+    mCore->mDequeueCondition.notify_all();
     return NO_ERROR;
 }
 
 status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) {
     ATRACE_CALL();
 
-    if (outSlotMask == NULL) {
+    if (outSlotMask == nullptr) {
         BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL");
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned");
@@ -568,7 +568,7 @@
 
     BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height);
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mDefaultWidth = width;
     mCore->mDefaultHeight = height;
     return NO_ERROR;
@@ -582,7 +582,7 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
         BQ_LOGE("setMaxBufferCount: producer is already connected");
@@ -622,8 +622,8 @@
 
     sp<IConsumerListener> listener;
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
-        mCore->waitWhileAllocatingLocked();
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked(lock);
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned");
@@ -673,7 +673,7 @@
         }
     }
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -683,7 +683,7 @@
 status_t BufferQueueConsumer::setConsumerName(const String8& name) {
     ATRACE_CALL();
     BQ_LOGV("setConsumerName: '%s'", name.string());
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mConsumerName = name;
     mConsumerName = name;
     return NO_ERROR;
@@ -692,7 +692,7 @@
 status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
     ATRACE_CALL();
     BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mDefaultBufferFormat = defaultFormat;
     return NO_ERROR;
 }
@@ -701,7 +701,7 @@
         android_dataspace defaultDataSpace) {
     ATRACE_CALL();
     BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mDefaultBufferDataSpace = defaultDataSpace;
     return NO_ERROR;
 }
@@ -709,7 +709,7 @@
 status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) {
     ATRACE_CALL();
     BQ_LOGV("setConsumerUsageBits: %#" PRIx64, usage);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mConsumerUsageBits = usage;
     return NO_ERROR;
 }
@@ -717,7 +717,7 @@
 status_t BufferQueueConsumer::setConsumerIsProtected(bool isProtected) {
     ATRACE_CALL();
     BQ_LOGV("setConsumerIsProtected: %s", isProtected ? "true" : "false");
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mConsumerIsProtected = isProtected;
     return NO_ERROR;
 }
@@ -725,26 +725,26 @@
 status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
     ATRACE_CALL();
     BQ_LOGV("setTransformHint: %#x", hint);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mTransformHint = hint;
     return NO_ERROR;
 }
 
 status_t BufferQueueConsumer::getSidebandStream(sp<NativeHandle>* outStream) const {
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     *outStream = mCore->mSidebandStream;
     return NO_ERROR;
 }
 
 status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush,
         std::vector<OccupancyTracker::Segment>* outHistory) {
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     *outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush);
     return NO_ERROR;
 }
 
 status_t BufferQueueConsumer::discardFreeBuffers() {
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->discardFreeBuffersLocked();
     return NO_ERROR;
 }
@@ -758,21 +758,31 @@
         return savedErrno ? -savedErrno : UNKNOWN_ERROR;
     }
 
-    const IPCThreadState* ipc = IPCThreadState::self();
-    const uid_t uid = ipc->getCallingUid();
+    bool denied = false;
+    const uid_t uid = BufferQueueThreadState::getCallingUid();
 #ifndef __ANDROID_VNDK__
     // permission check can't be done for vendors as vendors have no access to
-    // the PermissionController
-    const pid_t pid = ipc->getCallingPid();
-    if ((uid != shellUid) &&
-        !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
-        outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
-                "from pid=%d, uid=%d\n", pid, uid);
+    // the PermissionController. We need to do a runtime check as well, since
+    // the system variant of libgui can be loaded in a vendor process. For eg:
+    // if a HAL uses an llndk library that depends on libgui (libmediandk etc).
+    if (!android_is_in_vendor_process()) {
+        const pid_t pid = BufferQueueThreadState::getCallingPid();
+        if ((uid != shellUid) &&
+            !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+            outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
+                                    "from pid=%d, uid=%d\n",
+                                    pid, uid);
+            denied = true;
+        }
+    }
 #else
     if (uid != shellUid) {
+        denied = true;
+    }
 #endif
+    if (denied) {
         android_errorWriteWithInfoLog(0x534e4554, "27046057",
-                static_cast<int32_t>(uid), NULL, 0);
+                static_cast<int32_t>(uid), nullptr, 0);
         return PERMISSION_DENIED;
     }
 
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index bb703da..e0e3431 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -73,6 +73,8 @@
     mActiveBuffers(),
     mDequeueCondition(),
     mDequeueBufferCannotBlock(false),
+    mQueueBufferCanDrop(false),
+    mLegacyBufferDrop(true),
     mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
     mDefaultWidth(1),
     mDefaultHeight(1),
@@ -110,13 +112,15 @@
 BufferQueueCore::~BufferQueueCore() {}
 
 void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
 
     outResult->appendFormat("%s- BufferQueue ", prefix.string());
     outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
                             mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
     outResult->appendFormat("%s  mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
                             mDequeueBufferCannotBlock, mAsyncMode);
+    outResult->appendFormat("%s  mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(),
+                            mQueueBufferCanDrop, mLegacyBufferDrop);
     outResult->appendFormat("%s  default-size=[%dx%d] default-format=%d ", prefix.string(),
                             mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
     outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
@@ -306,10 +310,10 @@
     return true;
 }
 
-void BufferQueueCore::waitWhileAllocatingLocked() const {
+void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const {
     ATRACE_CALL();
     while (mIsAllocating) {
-        mIsAllocatingCondition.wait(mMutex);
+        mIsAllocatingCondition.wait(lock);
     }
 }
 
@@ -349,7 +353,7 @@
                 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer != NULL) {
+            if (mSlots[slot].mGraphicBuffer != nullptr) {
                 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
                         slot);
                 usleep(PAUSE_TIME);
@@ -371,7 +375,7 @@
                 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer != NULL) {
+            if (mSlots[slot].mGraphicBuffer != nullptr) {
                 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
                         slot);
                 usleep(PAUSE_TIME);
@@ -394,7 +398,7 @@
                 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer == NULL) {
+            if (mSlots[slot].mGraphicBuffer == nullptr) {
                 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
                 usleep(PAUSE_TIME);
             }
@@ -418,7 +422,7 @@
                 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
+            if (mSlots[slot].mGraphicBuffer == nullptr && !mIsAllocating) {
                 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
                 usleep(PAUSE_TIME);
             }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9d7f14c..9c311a3 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -35,6 +35,7 @@
 #include <gui/GLConsumer.h>
 #include <gui/IConsumerListener.h>
 #include <gui/IProducerListener.h>
+#include <private/gui/BufferQueueThreadState.h>
 
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -58,14 +59,15 @@
     mNextCallbackTicket(0),
     mCurrentCallbackTicket(0),
     mCallbackCondition(),
-    mDequeueTimeout(-1) {}
+    mDequeueTimeout(-1),
+    mDequeueWaitingForAllocation(false) {}
 
 BufferQueueProducer::~BufferQueueProducer() {}
 
 status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
     ATRACE_CALL();
     BQ_LOGV("requestBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("requestBuffer: BufferQueue has been abandoned");
@@ -100,8 +102,8 @@
 
     sp<IConsumerListener> listener;
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
-        mCore->waitWhileAllocatingLocked();
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked(lock);
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been "
@@ -162,11 +164,11 @@
         if (delta < 0) {
             listener = mCore->mConsumerListener;
         }
-        mCore->mDequeueCondition.broadcast();
+        mCore->mDequeueCondition.notify_all();
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -179,8 +181,8 @@
 
     sp<IConsumerListener> listener;
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
-        mCore->waitWhileAllocatingLocked();
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked(lock);
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("setAsyncMode: BufferQueue has been abandoned");
@@ -214,14 +216,14 @@
         }
         mCore->mAsyncMode = async;
         VALIDATE_CONSISTENCY();
-        mCore->mDequeueCondition.broadcast();
+        mCore->mDequeueCondition.notify_all();
         if (delta < 0) {
             listener = mCore->mConsumerListener;
         }
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
     return NO_ERROR;
@@ -246,7 +248,7 @@
 }
 
 status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
-        int* found) const {
+        std::unique_lock<std::mutex>& lock, int* found) const {
     auto callerString = (caller == FreeSlotCaller::Dequeue) ?
             "dequeueBuffer" : "attachBuffer";
     bool tryAgain = true;
@@ -272,8 +274,12 @@
         // This check is only done if a buffer has already been queued
         if (mCore->mBufferHasBeenQueued &&
                 dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
-            BQ_LOGE("%s: attempting to exceed the max dequeued buffer count "
-                    "(%d)", callerString, mCore->mMaxDequeuedBufferCount);
+            // Supress error logs when timeout is non-negative.
+            if (mDequeueTimeout < 0) {
+                BQ_LOGE("%s: attempting to exceed the max dequeued buffer "
+                        "count (%d)", callerString,
+                        mCore->mMaxDequeuedBufferCount);
+            }
             return INVALID_OPERATION;
         }
 
@@ -333,13 +339,13 @@
                 return WOULD_BLOCK;
             }
             if (mDequeueTimeout >= 0) {
-                status_t result = mCore->mDequeueCondition.waitRelative(
-                        mCore->mMutex, mDequeueTimeout);
-                if (result == TIMED_OUT) {
-                    return result;
+                std::cv_status result = mCore->mDequeueCondition.wait_for(lock,
+                        std::chrono::nanoseconds(mDequeueTimeout));
+                if (result == std::cv_status::timeout) {
+                    return TIMED_OUT;
                 }
             } else {
-                mCore->mDequeueCondition.wait(mCore->mMutex);
+                mCore->mDequeueCondition.wait(lock);
             }
         }
     } // while (tryAgain)
@@ -353,7 +359,7 @@
                                             FrameEventHistoryDelta* outTimestamps) {
     ATRACE_CALL();
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
         mConsumerName = mCore->mConsumerName;
 
         if (mCore->mIsAbandoned) {
@@ -380,7 +386,16 @@
     bool attachedByConsumer = false;
 
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
+
+        // If we don't have a free buffer, but we are currently allocating, we wait until allocation
+        // is finished such that we don't allocate in parallel.
+        if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
+            mDequeueWaitingForAllocation = true;
+            mCore->waitWhileAllocatingLocked(lock);
+            mDequeueWaitingForAllocation = false;
+            mDequeueWaitingForAllocationCondition.notify_all();
+        }
 
         if (format == 0) {
             format = mCore->mDefaultBufferFormat;
@@ -397,8 +412,7 @@
 
         int found = BufferItem::INVALID_BUFFER_SLOT;
         while (found == BufferItem::INVALID_BUFFER_SLOT) {
-            status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
-                    &found);
+            status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
             if (status != NO_ERROR) {
                 return status;
             }
@@ -449,11 +463,11 @@
 
         mSlots[found].mBufferState.dequeue();
 
-        if ((buffer == NULL) ||
+        if ((buffer == nullptr) ||
                 buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
         {
             mSlots[found].mAcquireCalled = false;
-            mSlots[found].mGraphicBuffer = NULL;
+            mSlots[found].mGraphicBuffer = nullptr;
             mSlots[found].mRequestBufferCalled = false;
             mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
             mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
@@ -471,7 +485,7 @@
         BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
                 mCore->mBufferAge);
 
-        if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
+        if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
             BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
                     "slot=%d w=%d h=%d format=%u",
                     found, buffer->width, buffer->height, buffer->format);
@@ -505,7 +519,7 @@
         status_t error = graphicBuffer->initCheck();
 
         { // Autolock scope
-            Mutex::Autolock lock(mCore->mMutex);
+            std::lock_guard<std::mutex> lock(mCore->mMutex);
 
             if (error == NO_ERROR && !mCore->mIsAbandoned) {
                 graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
@@ -513,7 +527,7 @@
             }
 
             mCore->mIsAllocating = false;
-            mCore->mIsAllocatingCondition.broadcast();
+            mCore->mIsAllocatingCondition.notify_all();
 
             if (error != NO_ERROR) {
                 mCore->mFreeSlots.insert(*outSlot);
@@ -572,7 +586,7 @@
 
     sp<IConsumerListener> listener;
     {
-        Mutex::Autolock lock(mCore->mMutex);
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
@@ -607,12 +621,12 @@
         mCore->mActiveBuffers.erase(slot);
         mCore->mFreeSlots.insert(slot);
         mCore->clearBufferSlotLocked(slot);
-        mCore->mDequeueCondition.broadcast();
+        mCore->mDequeueCondition.notify_all();
         VALIDATE_CONSISTENCY();
         listener = mCore->mConsumerListener;
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -623,17 +637,17 @@
         sp<Fence>* outFence) {
     ATRACE_CALL();
 
-    if (outBuffer == NULL) {
+    if (outBuffer == nullptr) {
         BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
         return BAD_VALUE;
-    } else if (outFence == NULL) {
+    } else if (outFence == nullptr) {
         BQ_LOGE("detachNextBuffer: outFence must not be NULL");
         return BAD_VALUE;
     }
 
     sp<IConsumerListener> listener;
     {
-        Mutex::Autolock lock(mCore->mMutex);
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
@@ -651,7 +665,7 @@
             return BAD_VALUE;
         }
 
-        mCore->waitWhileAllocatingLocked();
+        mCore->waitWhileAllocatingLocked(lock);
 
         if (mCore->mFreeBuffers.empty()) {
             return NO_MEMORY;
@@ -670,7 +684,7 @@
         listener = mCore->mConsumerListener;
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -681,15 +695,15 @@
         const sp<android::GraphicBuffer>& buffer) {
     ATRACE_CALL();
 
-    if (outSlot == NULL) {
+    if (outSlot == nullptr) {
         BQ_LOGE("attachBuffer: outSlot must not be NULL");
         return BAD_VALUE;
-    } else if (buffer == NULL) {
+    } else if (buffer == nullptr) {
         BQ_LOGE("attachBuffer: cannot attach NULL buffer");
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::unique_lock<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("attachBuffer: BufferQueue has been abandoned");
@@ -713,11 +727,11 @@
         return BAD_VALUE;
     }
 
-    mCore->waitWhileAllocatingLocked();
+    mCore->waitWhileAllocatingLocked(lock);
 
     status_t returnFlags = NO_ERROR;
     int found;
-    status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found);
+    status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, lock, &found);
     if (status != NO_ERROR) {
         return status;
     }
@@ -766,7 +780,7 @@
     const Region& surfaceDamage = input.getSurfaceDamage();
     const HdrMetadata& hdrMetadata = input.getHdrMetadata();
 
-    if (acquireFence == NULL) {
+    if (acquireFence == nullptr) {
         BQ_LOGE("queueBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -790,7 +804,7 @@
     uint64_t currentFrameNumber = 0;
     BufferItem item;
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
 
         if (mCore->mIsAbandoned) {
             BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
@@ -872,7 +886,8 @@
         item.mFence = acquireFence;
         item.mFenceTime = acquireFenceTime;
         item.mIsDroppable = mCore->mAsyncMode ||
-                mCore->mDequeueBufferCannotBlock ||
+                (mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
+                (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
                 (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
         item.mSurfaceDamage = surfaceDamage;
         item.mQueuedBuffer = true;
@@ -931,7 +946,7 @@
         }
 
         mCore->mBufferHasBeenQueued = true;
-        mCore->mDequeueCondition.broadcast();
+        mCore->mDequeueCondition.notify_all();
         mCore->mLastQueuedSlot = slot;
 
         output->width = mCore->mDefaultWidth;
@@ -957,9 +972,6 @@
         item.mGraphicBuffer.clear();
     }
 
-    // Don't send the slot number through the callback since the consumer shouldn't need it
-    item.mSlot = BufferItem::INVALID_BUFFER_SLOT;
-
     // Call back without the main BufferQueue lock held, but with the callback
     // lock held so we can ensure that callbacks occur in order
 
@@ -967,14 +979,14 @@
     sp<Fence> lastQueuedFence;
 
     { // scope for the lock
-        Mutex::Autolock lock(mCallbackMutex);
+        std::unique_lock<std::mutex> lock(mCallbackMutex);
         while (callbackTicket != mCurrentCallbackTicket) {
-            mCallbackCondition.wait(mCallbackMutex);
+            mCallbackCondition.wait(lock);
         }
 
-        if (frameAvailableListener != NULL) {
+        if (frameAvailableListener != nullptr) {
             frameAvailableListener->onFrameAvailable(item);
-        } else if (frameReplacedListener != NULL) {
+        } else if (frameReplacedListener != nullptr) {
             frameReplacedListener->onFrameReplaced(item);
         }
 
@@ -986,7 +998,7 @@
         mLastQueuedTransform = item.mTransform;
 
         ++mCurrentCallbackTicket;
-        mCallbackCondition.broadcast();
+        mCallbackCondition.notify_all();
     }
 
     // Update and get FrameEventHistory.
@@ -1014,7 +1026,7 @@
 status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
     ATRACE_CALL();
     BQ_LOGV("cancelBuffer: slot %d", slot);
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     if (mCore->mIsAbandoned) {
         BQ_LOGE("cancelBuffer: BufferQueue has been abandoned");
@@ -1039,7 +1051,7 @@
         BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
                 "(state = %s)", slot, mSlots[slot].mBufferState.string());
         return BAD_VALUE;
-    } else if (fence == NULL) {
+    } else if (fence == nullptr) {
         BQ_LOGE("cancelBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -1059,7 +1071,7 @@
     }
 
     mSlots[slot].mFence = fence;
-    mCore->mDequeueCondition.broadcast();
+    mCore->mDequeueCondition.notify_all();
     VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
@@ -1067,9 +1079,9 @@
 
 int BufferQueueProducer::query(int what, int *outValue) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
-    if (outValue == NULL) {
+    if (outValue == nullptr) {
         BQ_LOGE("query: outValue was NULL");
         return BAD_VALUE;
     }
@@ -1135,7 +1147,7 @@
 status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
         int api, bool producerControlledByApp, QueueBufferOutput *output) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mConsumerName = mCore->mConsumerName;
     BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
             producerControlledByApp ? "true" : "false");
@@ -1145,12 +1157,12 @@
         return NO_INIT;
     }
 
-    if (mCore->mConsumerListener == NULL) {
+    if (mCore->mConsumerListener == nullptr) {
         BQ_LOGE("connect: BufferQueue has no consumer");
         return NO_INIT;
     }
 
-    if (output == NULL) {
+    if (output == nullptr) {
         BQ_LOGE("connect: output was NULL");
         return BAD_VALUE;
     }
@@ -1188,10 +1200,10 @@
             output->nextFrameNumber = mCore->mFrameCounter + 1;
             output->bufferReplaced = false;
 
-            if (listener != NULL) {
+            if (listener != nullptr) {
                 // Set up a death notification so that we can disconnect
                 // automatically if the remote producer dies
-                if (IInterface::asBinder(listener)->remoteBinder() != NULL) {
+                if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
                     status = IInterface::asBinder(listener)->linkToDeath(
                             static_cast<IBinder::DeathRecipient*>(this));
                     if (status != NO_ERROR) {
@@ -1210,12 +1222,14 @@
             status = BAD_VALUE;
             break;
     }
-    mCore->mConnectedPid = IPCThreadState::self()->getCallingPid();
+    mCore->mConnectedPid = BufferQueueThreadState::getCallingPid();
     mCore->mBufferHasBeenQueued = false;
     mCore->mDequeueBufferCannotBlock = false;
-    if (mDequeueTimeout < 0) {
-        mCore->mDequeueBufferCannotBlock =
-                mCore->mConsumerControlledByApp && producerControlledByApp;
+    mCore->mQueueBufferCanDrop = false;
+    mCore->mLegacyBufferDrop = true;
+    if (mCore->mConsumerControlledByApp && producerControlledByApp) {
+        mCore->mDequeueBufferCannotBlock = mDequeueTimeout < 0;
+        mCore->mQueueBufferCanDrop = mDequeueTimeout <= 0;
     }
 
     mCore->mAllowAllocation = true;
@@ -1230,16 +1244,16 @@
     int status = NO_ERROR;
     sp<IConsumerListener> listener;
     { // Autolock scope
-        Mutex::Autolock lock(mCore->mMutex);
+        std::unique_lock<std::mutex> lock(mCore->mMutex);
 
         if (mode == DisconnectMode::AllLocal) {
-            if (IPCThreadState::self()->getCallingPid() != mCore->mConnectedPid) {
+            if (BufferQueueThreadState::getCallingPid() != mCore->mConnectedPid) {
                 return NO_ERROR;
             }
             api = BufferQueueCore::CURRENTLY_CONNECTED_API;
         }
 
-        mCore->waitWhileAllocatingLocked();
+        mCore->waitWhileAllocatingLocked(lock);
 
         if (mCore->mIsAbandoned) {
             // It's not really an error to disconnect after the surface has
@@ -1268,7 +1282,7 @@
                     mCore->freeAllBuffersLocked();
 
                     // Remove our death notification callback if we have one
-                    if (mCore->mLinkedToDeath != NULL) {
+                    if (mCore->mLinkedToDeath != nullptr) {
                         sp<IBinder> token =
                                 IInterface::asBinder(mCore->mLinkedToDeath);
                         // This can fail if we're here because of the death
@@ -1278,12 +1292,12 @@
                     }
                     mCore->mSharedBufferSlot =
                             BufferQueueCore::INVALID_BUFFER_SLOT;
-                    mCore->mLinkedToDeath = NULL;
-                    mCore->mConnectedProducerListener = NULL;
+                    mCore->mLinkedToDeath = nullptr;
+                    mCore->mConnectedProducerListener = nullptr;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
                     mCore->mConnectedPid = -1;
                     mCore->mSidebandStream.clear();
-                    mCore->mDequeueCondition.broadcast();
+                    mCore->mDequeueCondition.notify_all();
                     listener = mCore->mConsumerListener;
                 } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
                     BQ_LOGE("disconnect: not connected (req=%d)", api);
@@ -1302,7 +1316,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
         listener->onDisconnect();
     }
@@ -1313,12 +1327,12 @@
 status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
     sp<IConsumerListener> listener;
     { // Autolock scope
-        Mutex::Autolock _l(mCore->mMutex);
+        std::lock_guard<std::mutex> _l(mCore->mMutex);
         mCore->mSidebandStream = stream;
         listener = mCore->mConsumerListener;
     } // Autolock scope
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onSidebandStreamChanged();
     }
     return NO_ERROR;
@@ -1335,8 +1349,8 @@
         uint64_t allocUsage = 0;
         std::string allocName;
         { // Autolock scope
-            Mutex::Autolock lock(mCore->mMutex);
-            mCore->waitWhileAllocatingLocked();
+            std::unique_lock<std::mutex> lock(mCore->mMutex);
+            mCore->waitWhileAllocatingLocked(lock);
 
             if (!mCore->mAllowAllocation) {
                 BQ_LOGE("allocateBuffers: allocation is not allowed for this "
@@ -1371,16 +1385,16 @@
             if (result != NO_ERROR) {
                 BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
                         " %u, usage %#" PRIx64 ")", width, height, format, usage);
-                Mutex::Autolock lock(mCore->mMutex);
+                std::lock_guard<std::mutex> lock(mCore->mMutex);
                 mCore->mIsAllocating = false;
-                mCore->mIsAllocatingCondition.broadcast();
+                mCore->mIsAllocatingCondition.notify_all();
                 return;
             }
             buffers.push_back(graphicBuffer);
         }
 
         { // Autolock scope
-            Mutex::Autolock lock(mCore->mMutex);
+            std::unique_lock<std::mutex> lock(mCore->mMutex);
             uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
             uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
             PixelFormat checkFormat = format != 0 ?
@@ -1391,7 +1405,7 @@
                 // Something changed while we released the lock. Retry.
                 BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
                 mCore->mIsAllocating = false;
-                mCore->mIsAllocatingCondition.broadcast();
+                mCore->mIsAllocatingCondition.notify_all();
                 continue;
             }
 
@@ -1419,8 +1433,14 @@
             }
 
             mCore->mIsAllocating = false;
-            mCore->mIsAllocatingCondition.broadcast();
+            mCore->mIsAllocatingCondition.notify_all();
             VALIDATE_CONSISTENCY();
+
+            // If dequeue is waiting for to allocate a buffer, release the lock until it's not
+            // waiting anymore so it can use the buffer we just allocated.
+            while (mDequeueWaitingForAllocation) {
+                mDequeueWaitingForAllocationCondition.wait(lock);
+            }
         } // Autolock scope
     }
 }
@@ -1429,7 +1449,7 @@
     ATRACE_CALL();
     BQ_LOGV("allowAllocation: %s", allow ? "true" : "false");
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mAllowAllocation = allow;
     return NO_ERROR;
 }
@@ -1438,14 +1458,14 @@
     ATRACE_CALL();
     BQ_LOGV("setGenerationNumber: %u", generationNumber);
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     mCore->mGenerationNumber = generationNumber;
     return NO_ERROR;
 }
 
 String8 BufferQueueProducer::getConsumerName() const {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     BQ_LOGV("getConsumerName: %s", mConsumerName.string());
     return mConsumerName;
 }
@@ -1454,7 +1474,7 @@
     ATRACE_CALL();
     BQ_LOGV("setSharedBufferMode: %d", sharedBufferMode);
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     if (!sharedBufferMode) {
         mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
     }
@@ -1466,7 +1486,7 @@
     ATRACE_CALL();
     BQ_LOGV("setAutoRefresh: %d", autoRefresh);
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
 
     mCore->mAutoRefresh = autoRefresh;
     return NO_ERROR;
@@ -1476,8 +1496,10 @@
     ATRACE_CALL();
     BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
 
-    Mutex::Autolock lock(mCore->mMutex);
-    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    bool dequeueBufferCannotBlock =
+            timeout >= 0 ? false : mCore->mDequeueBufferCannotBlock;
+    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, dequeueBufferCannotBlock,
             mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
     if (!mCore->adjustAvailableSlotsLocked(delta)) {
         BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number of "
@@ -1486,18 +1508,30 @@
     }
 
     mDequeueTimeout = timeout;
-    mCore->mDequeueBufferCannotBlock = false;
+    mCore->mDequeueBufferCannotBlock = dequeueBufferCannotBlock;
+    if (timeout > 0) {
+        mCore->mQueueBufferCanDrop = false;
+    }
 
     VALIDATE_CONSISTENCY();
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::setLegacyBufferDrop(bool drop) {
+    ATRACE_CALL();
+    BQ_LOGV("setLegacyBufferDrop: drop = %d", drop);
+
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    mCore->mLegacyBufferDrop = drop;
+    return NO_ERROR;
+}
+
 status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
         sp<Fence>* outFence, float outTransformMatrix[16]) {
     ATRACE_CALL();
     BQ_LOGV("getLastQueuedBuffer");
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) {
         *outBuffer = nullptr;
         *outFence = Fence::NO_FENCE;
@@ -1533,10 +1567,10 @@
     BQ_LOGV("addAndGetFrameTimestamps");
     sp<IConsumerListener> listener;
     {
-        Mutex::Autolock lock(mCore->mMutex);
+        std::lock_guard<std::mutex> lock(mCore->mMutex);
         listener = mCore->mConsumerListener;
     }
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
 }
@@ -1560,7 +1594,7 @@
 status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const {
     BQ_LOGV("getConsumerUsage");
 
-    Mutex::Autolock lock(mCore->mMutex);
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
     *outUsage = mCore->mConsumerUsageBits;
     return NO_ERROR;
 }
diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp
new file mode 100644
index 0000000..3b531ec
--- /dev/null
+++ b/libs/gui/BufferQueueThreadState.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <private/gui/BufferQueueThreadState.h>
+#include <unistd.h>
+
+namespace android {
+
+uid_t BufferQueueThreadState::getCallingUid() {
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        return hardware::IPCThreadState::self()->getCallingUid();
+    }
+    return IPCThreadState::self()->getCallingUid();
+}
+
+pid_t BufferQueueThreadState::getCallingPid() {
+    if (hardware::IPCThreadState::self()->isServingCall()) {
+        return hardware::IPCThreadState::self()->getCallingPid();
+    }
+    return IPCThreadState::self()->getCallingPid();
+}
+
+} // namespace android
diff --git a/libs/gui/CleanSpec.mk b/libs/gui/CleanSpec.mk
deleted file mode 100644
index 5a5144c..0000000
--- a/libs/gui/CleanSpec.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2012 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.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list.  These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list.  E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index f9e292e..abd9921 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -96,7 +96,7 @@
 
 void ConsumerBase::freeBufferLocked(int slotIndex) {
     CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
-    mSlots[slotIndex].mGraphicBuffer = 0;
+    mSlots[slotIndex].mGraphicBuffer = nullptr;
     mSlots[slotIndex].mFence = Fence::NO_FENCE;
     mSlots[slotIndex].mFrameNumber = 0;
 }
@@ -110,7 +110,7 @@
         listener = mFrameAvailableListener.promote();
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         CB_LOGV("actually calling onFrameAvailable");
         listener->onFrameAvailable(item);
     }
@@ -125,7 +125,7 @@
         listener = mFrameAvailableListener.promote();
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         CB_LOGV("actually calling onFrameReplaced");
         listener->onFrameReplaced(item);
     }
@@ -352,8 +352,8 @@
         return err;
     }
 
-    if (item->mGraphicBuffer != NULL) {
-        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+    if (item->mGraphicBuffer != nullptr) {
+        if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
             freeBufferLocked(item->mSlot);
         }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
@@ -468,7 +468,7 @@
     if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
         return false;
     }
-    return (mSlots[slot].mGraphicBuffer != NULL &&
+    return (mSlots[slot].mGraphicBuffer != nullptr &&
             mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
 }
 
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1757ec1..f5cf1c4 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -34,9 +34,9 @@
 
 DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (sf != NULL) {
+    if (sf != nullptr) {
         mEventConnection = sf->createDisplayEventConnection(vsyncSource);
-        if (mEventConnection != NULL) {
+        if (mEventConnection != nullptr) {
             mDataChannel = std::make_unique<gui::BitTube>();
             mEventConnection->stealReceiveChannel(mDataChannel.get());
         }
@@ -47,13 +47,13 @@
 }
 
 status_t DisplayEventReceiver::initCheck() const {
-    if (mDataChannel != NULL)
+    if (mDataChannel != nullptr)
         return NO_ERROR;
     return NO_INIT;
 }
 
 int DisplayEventReceiver::getFd() const {
-    if (mDataChannel == NULL)
+    if (mDataChannel == nullptr)
         return NO_INIT;
 
     return mDataChannel->getFd();
@@ -63,7 +63,7 @@
     if (int32_t(count) < 0)
         return BAD_VALUE;
 
-    if (mEventConnection != NULL) {
+    if (mEventConnection != nullptr) {
         mEventConnection->setVsyncRate(count);
         return NO_ERROR;
     }
@@ -71,7 +71,7 @@
 }
 
 status_t DisplayEventReceiver::requestNextVsync() {
-    if (mEventConnection != NULL) {
+    if (mEventConnection != nullptr) {
         mEventConnection->requestNextVsync();
         return NO_ERROR;
     }
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a379ad6..c04d907 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -18,10 +18,10 @@
 
 #define LOG_TAG "FrameEvents"
 
+#include <android-base/stringprintf.h>
 #include <cutils/compiler.h>  // For CC_[UN]LIKELY
 #include <inttypes.h>
 #include <utils/Log.h>
-#include <utils/String8.h>
 
 #include <algorithm>
 #include <limits>
@@ -29,6 +29,7 @@
 
 namespace android {
 
+using base::StringAppendF;
 
 // ============================================================================
 // FrameEvents
@@ -86,50 +87,49 @@
     releaseFence->getSignalTime();
 }
 
-static void dumpFenceTime(String8& outString, const char* name,
-        bool pending, const FenceTime& fenceTime) {
-    outString.appendFormat("--- %s", name);
+static void dumpFenceTime(std::string& outString, const char* name, bool pending,
+                          const FenceTime& fenceTime) {
+    StringAppendF(&outString, "--- %s", name);
     nsecs_t signalTime = fenceTime.getCachedSignalTime();
     if (Fence::isValidTimestamp(signalTime)) {
-        outString.appendFormat("%" PRId64 "\n", signalTime);
+        StringAppendF(&outString, "%" PRId64 "\n", signalTime);
     } else if (pending || signalTime == Fence::SIGNAL_TIME_PENDING) {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     } else if (&fenceTime == FenceTime::NO_FENCE.get()){
-        outString.appendFormat("N/A\n");
+        outString.append("N/A\n");
     } else {
-        outString.appendFormat("Error\n");
+        outString.append("Error\n");
     }
 }
 
-void FrameEvents::dump(String8& outString) const
-{
+void FrameEvents::dump(std::string& outString) const {
     if (!valid) {
         return;
     }
 
-    outString.appendFormat("-- Frame %" PRIu64 "\n", frameNumber);
-    outString.appendFormat("--- Posted      \t%" PRId64 "\n", postedTime);
-    outString.appendFormat("--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
+    StringAppendF(&outString, "-- Frame %" PRIu64 "\n", frameNumber);
+    StringAppendF(&outString, "--- Posted      \t%" PRId64 "\n", postedTime);
+    StringAppendF(&outString, "--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
 
-    outString.appendFormat("--- Latched     \t");
+    outString.append("--- Latched     \t");
     if (FrameEvents::isValidTimestamp(latchTime)) {
-        outString.appendFormat("%" PRId64 "\n", latchTime);
+        StringAppendF(&outString, "%" PRId64 "\n", latchTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
-    outString.appendFormat("--- Refresh (First)\t");
+    outString.append("--- Refresh (First)\t");
     if (FrameEvents::isValidTimestamp(firstRefreshStartTime)) {
-        outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime);
+        StringAppendF(&outString, "%" PRId64 "\n", firstRefreshStartTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
-    outString.appendFormat("--- Refresh (Last)\t");
+    outString.append("--- Refresh (Last)\t");
     if (FrameEvents::isValidTimestamp(lastRefreshStartTime)) {
-        outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime);
+        StringAppendF(&outString, "%" PRId64 "\n", lastRefreshStartTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
     dumpFenceTime(outString, "Acquire           \t",
@@ -139,11 +139,11 @@
     dumpFenceTime(outString, "Display Present   \t",
             !addPostCompositeCalled, *displayPresentFence);
 
-    outString.appendFormat("--- DequeueReady  \t");
+    outString.append("--- DequeueReady  \t");
     if (FrameEvents::isValidTimestamp(dequeueReadyTime)) {
-        outString.appendFormat("%" PRId64 "\n", dequeueReadyTime);
+        StringAppendF(&outString, "%" PRId64 "\n", dequeueReadyTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
     dumpFenceTime(outString, "Release           \t",
@@ -158,7 +158,7 @@
 namespace {
 
 struct FrameNumberEqual {
-    FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
+    explicit FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
     bool operator()(const FrameEvents& frame) {
         return frame.valid && mFrameNumber == frame.frameNumber;
     }
@@ -206,11 +206,11 @@
     return lhs.valid;
 }
 
-void FrameEventHistory::dump(String8& outString) const {
+void FrameEventHistory::dump(std::string& outString) const {
     auto earliestFrame = std::min_element(
             mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
     if (!earliestFrame->valid) {
-        outString.appendFormat("-- N/A\n");
+        outString.append("-- N/A\n");
         return;
     }
     for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
@@ -621,7 +621,7 @@
 // ============================================================================
 
 FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
-        FrameEventHistoryDelta&& src) {
+        FrameEventHistoryDelta&& src) noexcept {
     mCompositorTiming = src.mCompositorTiming;
 
     if (CC_UNLIKELY(!mDeltas.empty())) {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 885efec..8d66154 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -46,7 +46,6 @@
 #include <utils/Trace.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
 
@@ -82,26 +81,6 @@
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
 
-static bool hasEglAndroidImageCropImpl() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
-    bool atEnd = (cropExtLen+1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglAndroidImageCrop() {
-    // Only compute whether the extension is present once the first time this
-    // function is called.
-    static bool hasIt = hasEglAndroidImageCropImpl();
-    return hasIt;
-}
-
 static bool hasEglProtectedContentImpl() {
     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
@@ -122,10 +101,6 @@
     return hasIt;
 }
 
-static bool isEglImageCroppable(const Rect& crop) {
-    return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
-}
-
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
@@ -291,7 +266,7 @@
             return err;
         }
 
-        if (mReleasedTexImage == NULL) {
+        if (mReleasedTexImage == nullptr) {
             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
         }
 
@@ -321,7 +296,7 @@
 
 sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
     Mutex::Autolock _l(sStaticInitLock);
-    if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
+    if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
         // The first time, create the debug texture in case the application
         // continues to use it.
         sp<GraphicBuffer> buffer = new GraphicBuffer(
@@ -357,7 +332,7 @@
     // If item->mGraphicBuffer is not null, this buffer has not been acquired
     // before, so any prior EglImage created is using a stale buffer. This
     // replaces any old EglImage with a new one (using the new buffer).
-    if (item->mGraphicBuffer != NULL) {
+    if (item->mGraphicBuffer != nullptr) {
         int slot = item->mSlot;
         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
     }
@@ -406,7 +381,7 @@
     // ConsumerBase.
     // We may have to do this even when item.mGraphicBuffer == NULL (which
     // means the buffer was previously acquired).
-    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
     if (err != NO_ERROR) {
         GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
                 mEglDisplay, slot);
@@ -430,8 +405,8 @@
     }
 
     GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
-            mCurrentTexture, mCurrentTextureImage != NULL ?
-                    mCurrentTextureImage->graphicBufferHandle() : 0,
+            mCurrentTexture, mCurrentTextureImage != nullptr ?
+                    mCurrentTextureImage->graphicBufferHandle() : nullptr,
             slot, mSlots[slot].mGraphicBuffer->handle);
 
     // Hang onto the pointer so that it isn't freed in the call to
@@ -491,13 +466,12 @@
 
     glBindTexture(mTexTarget, mTexName);
     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
-            mCurrentTextureImage == NULL) {
+            mCurrentTextureImage == nullptr) {
         GLC_LOGE("bindTextureImage: no currently-bound texture");
         return NO_INIT;
     }
 
-    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                        mCurrentCrop);
+    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
     if (err != NO_ERROR) {
         GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                 mEglDisplay, mCurrentTexture);
@@ -511,9 +485,7 @@
     // forcing the creation of a new image.
     if ((error = glGetError()) != GL_NO_ERROR) {
         glBindTexture(mTexTarget, mTexName);
-        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                               mCurrentCrop,
-                                                               true);
+        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
         if (result != NO_ERROR) {
             GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                     mEglDisplay, mCurrentTexture);
@@ -655,7 +627,7 @@
     mTexName = tex;
     mAttached = true;
 
-    if (mCurrentTextureImage != NULL) {
+    if (mCurrentTextureImage != nullptr) {
         // This may wait for a buffer a second time. This is likely required if
         // this is a different context, since otherwise the wait could be skipped
         // by bouncing through another context. For the same context the extra
@@ -676,7 +648,7 @@
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
         if (SyncFeatures::getInstance().useNativeFenceSync()) {
             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
-                    EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+                    EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
             if (sync == EGL_NO_SYNC_KHR) {
                 GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
                         eglGetError());
@@ -720,7 +692,7 @@
 
             // Create a fence for the outstanding accesses in the current
             // OpenGL ES context.
-            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
             if (fence == EGL_NO_SYNC_KHR) {
                 GLC_LOGE("syncForReleaseLocked: error creating fence: %#x",
                         eglGetError());
@@ -752,11 +724,11 @@
     bool needsRecompute = mFilteringEnabled != enabled;
     mFilteringEnabled = enabled;
 
-    if (needsRecompute && mCurrentTextureImage==NULL) {
+    if (needsRecompute && mCurrentTextureImage==nullptr) {
         GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
     }
 
-    if (needsRecompute && mCurrentTextureImage != NULL) {
+    if (needsRecompute && mCurrentTextureImage != nullptr) {
         computeCurrentTransformMatrixLocked();
     }
 }
@@ -769,109 +741,10 @@
         GLC_LOGD("computeCurrentTransformMatrixLocked: "
                 "mCurrentTextureImage is NULL");
     }
-    computeTransformMatrix(mCurrentTransformMatrix, buf,
-        isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
+    computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
         mCurrentTransform, mFilteringEnabled);
 }
 
-void GLConsumer::computeTransformMatrix(float outTransform[16],
-        const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
-        bool filtering) {
-    // Transform matrices
-    static const mat4 mtxFlipH(
-        -1, 0, 0, 0,
-        0, 1, 0, 0,
-        0, 0, 1, 0,
-        1, 0, 0, 1
-    );
-    static const mat4 mtxFlipV(
-        1, 0, 0, 0,
-        0, -1, 0, 0,
-        0, 0, 1, 0,
-        0, 1, 0, 1
-    );
-    static const mat4 mtxRot90(
-        0, 1, 0, 0,
-        -1, 0, 0, 0,
-        0, 0, 1, 0,
-        1, 0, 0, 1
-    );
-
-    mat4 xform;
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        xform *= mtxFlipH;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        xform *= mtxFlipV;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        xform *= mtxRot90;
-    }
-
-    if (!cropRect.isEmpty()) {
-        float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
-        float bufferWidth = buf->getWidth();
-        float bufferHeight = buf->getHeight();
-        float shrinkAmount = 0.0f;
-        if (filtering) {
-            // In order to prevent bilinear sampling beyond the edge of the
-            // crop rectangle we may need to shrink it by 2 texels in each
-            // dimension.  Normally this would just need to take 1/2 a texel
-            // off each end, but because the chroma channels of YUV420 images
-            // are subsampled we may need to shrink the crop region by a whole
-            // texel on each side.
-            switch (buf->getPixelFormat()) {
-                case PIXEL_FORMAT_RGBA_8888:
-                case PIXEL_FORMAT_RGBX_8888:
-                case PIXEL_FORMAT_RGBA_FP16:
-                case PIXEL_FORMAT_RGBA_1010102:
-                case PIXEL_FORMAT_RGB_888:
-                case PIXEL_FORMAT_RGB_565:
-                case PIXEL_FORMAT_BGRA_8888:
-                    // We know there's no subsampling of any channels, so we
-                    // only need to shrink by a half a pixel.
-                    shrinkAmount = 0.5;
-                    break;
-
-                default:
-                    // If we don't recognize the format, we must assume the
-                    // worst case (that we care about), which is YUV420.
-                    shrinkAmount = 1.0;
-                    break;
-            }
-        }
-
-        // Only shrink the dimensions that are not the size of the buffer.
-        if (cropRect.width() < bufferWidth) {
-            tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
-            sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
-                    bufferWidth;
-        }
-        if (cropRect.height() < bufferHeight) {
-            ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
-                    bufferHeight;
-            sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
-                    bufferHeight;
-        }
-
-        mat4 crop(
-            sx, 0, 0, 0,
-            0, sy, 0, 0,
-            0, 0, 1, 0,
-            tx, ty, 0, 1
-        );
-        xform = crop * xform;
-    }
-
-    // SurfaceFlinger expects the top of its window textures to be at a Y
-    // coordinate of 0, so GLConsumer must behave the same way.  We don't
-    // want to expose this to applications, however, so we must add an
-    // additional vertical flip to the transform after all the other transforms.
-    xform = mtxFlipV * xform;
-
-    memcpy(outTransform, xform.asArray(), sizeof(xform));
-}
-
 Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
     Rect outCrop = crop;
 
@@ -938,7 +811,7 @@
     }
 
     return (mCurrentTextureImage == nullptr) ?
-            NULL : mCurrentTextureImage->graphicBuffer();
+            nullptr : mCurrentTextureImage->graphicBuffer();
 }
 
 Rect GLConsumer::getCurrentCrop() const {
@@ -1063,8 +936,7 @@
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
-    mEglDisplay(EGL_NO_DISPLAY),
-    mCropRect(Rect::EMPTY_RECT) {
+    mEglDisplay(EGL_NO_DISPLAY) {
 }
 
 GLConsumer::EglImage::~EglImage() {
@@ -1077,13 +949,11 @@
 }
 
 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
-                                              const Rect& cropRect,
                                               bool forceCreation) {
     // If there's an image and it's no longer valid, destroy it.
     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
     bool displayInvalid = mEglDisplay != eglDisplay;
-    bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
-    if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
+    if (haveImage && (displayInvalid || forceCreation)) {
         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
         }
@@ -1095,14 +965,12 @@
     // If there's no image, create one.
     if (mEglImage == EGL_NO_IMAGE_KHR) {
         mEglDisplay = eglDisplay;
-        mCropRect = cropRect;
-        mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+        mEglImage = createImage(mEglDisplay, mGraphicBuffer);
     }
 
     // Fail if we can't create a valid image.
     if (mEglImage == EGL_NO_IMAGE_KHR) {
         mEglDisplay = EGL_NO_DISPLAY;
-        mCropRect.makeInvalid();
         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
@@ -1119,38 +987,19 @@
 }
 
 EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
-        const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+        const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf =
             static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
     const bool createProtectedImage =
             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) &&
             hasEglProtectedContent();
     EGLint attrs[] = {
-        EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
-        EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
-        EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
-        EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
-        EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
+        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
         createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
         createProtectedImage ? EGL_TRUE : EGL_NONE,
         EGL_NONE,
     };
-    if (!crop.isValid()) {
-        // No crop rect to set, so leave the crop out of the attrib array. Make
-        // sure to propagate the protected content attrs if they are set.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    } else if (!isEglImageCroppable(crop)) {
-        // The crop rect is not at the origin, so we can't set the crop on the
-        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-        // extension.  In the future we can add a layered extension that
-        // removes this restriction if there is hardware that can support it.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    }
-    eglInitialize(dpy, 0, 0);
+    eglInitialize(dpy, nullptr, nullptr);
     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
     if (image == EGL_NO_IMAGE_KHR) {
diff --git a/libs/gui/GLConsumerUtils.cpp b/libs/gui/GLConsumerUtils.cpp
new file mode 100644
index 0000000..7a06c3d
--- /dev/null
+++ b/libs/gui/GLConsumerUtils.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 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 "GLConsumerUtils"
+//#define LOG_NDEBUG 0
+
+#include <gui/GLConsumer.h>
+#include <math/mat4.h>
+#include <system/window.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void GLConsumer::computeTransformMatrix(float outTransform[16],
+        const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
+        bool filtering) {
+    // Transform matrices
+    static const mat4 mtxFlipH(
+        -1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+    static const mat4 mtxFlipV(
+        1, 0, 0, 0,
+        0, -1, 0, 0,
+        0, 0, 1, 0,
+        0, 1, 0, 1
+    );
+    static const mat4 mtxRot90(
+        0, 1, 0, 0,
+        -1, 0, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+
+    mat4 xform;
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        xform *= mtxFlipH;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        xform *= mtxFlipV;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        xform *= mtxRot90;
+    }
+
+    if (!cropRect.isEmpty()) {
+        float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
+        float bufferWidth = buf->getWidth();
+        float bufferHeight = buf->getHeight();
+        float shrinkAmount = 0.0f;
+        if (filtering) {
+            // In order to prevent bilinear sampling beyond the edge of the
+            // crop rectangle we may need to shrink it by 2 texels in each
+            // dimension.  Normally this would just need to take 1/2 a texel
+            // off each end, but because the chroma channels of YUV420 images
+            // are subsampled we may need to shrink the crop region by a whole
+            // texel on each side.
+            switch (buf->getPixelFormat()) {
+                case PIXEL_FORMAT_RGBA_8888:
+                case PIXEL_FORMAT_RGBX_8888:
+                case PIXEL_FORMAT_RGBA_FP16:
+                case PIXEL_FORMAT_RGBA_1010102:
+                case PIXEL_FORMAT_RGB_888:
+                case PIXEL_FORMAT_RGB_565:
+                case PIXEL_FORMAT_BGRA_8888:
+                    // We know there's no subsampling of any channels, so we
+                    // only need to shrink by a half a pixel.
+                    shrinkAmount = 0.5;
+                    break;
+
+                default:
+                    // If we don't recognize the format, we must assume the
+                    // worst case (that we care about), which is YUV420.
+                    shrinkAmount = 1.0;
+                    break;
+            }
+        }
+
+        // Only shrink the dimensions that are not the size of the buffer.
+        if (cropRect.width() < bufferWidth) {
+            tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+            sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
+                    bufferWidth;
+        }
+        if (cropRect.height() < bufferHeight) {
+            ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
+                    bufferHeight;
+            sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
+                    bufferHeight;
+        }
+
+        mat4 crop(
+            sx, 0, 0, 0,
+            0, sy, 0, 0,
+            0, 0, 1, 0,
+            tx, ty, 0, 1
+        );
+        xform = crop * xform;
+    }
+
+    // GLConsumer uses the GL convention where (0, 0) is the bottom-left
+    // corner and (1, 1) is the top-right corner.  Add an additional vertical
+    // flip after all other transforms to map from GL convention to buffer
+    // queue memory layout, where (0, 0) is the top-left corner.
+    xform = mtxFlipV * xform;
+
+    memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+}; // namespace android
diff --git a/libs/gui/GuiConfig.cpp b/libs/gui/GuiConfig.cpp
index bc0c83c..3ec20ee 100644
--- a/libs/gui/GuiConfig.cpp
+++ b/libs/gui/GuiConfig.cpp
@@ -18,8 +18,7 @@
 
 namespace android {
 
-void appendGuiConfigString(String8& configStr)
-{
+void appendGuiConfigString(std::string& configStr) {
     static const char* config =
             " [libgui"
 #ifdef DONT_USE_FENCE_SYNC
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
index b715e43..add3ef0 100644
--- a/libs/gui/HdrMetadata.cpp
+++ b/libs/gui/HdrMetadata.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <gui/HdrMetadata.h>
+#include <limits>
 
 namespace android {
 
@@ -26,6 +27,10 @@
     if (validTypes & CTA861_3) {
         size += sizeof(cta8613);
     }
+    if (validTypes & HDR10PLUS) {
+        size += sizeof(size_t);
+        size += hdr10plus.size();
+    }
     return size;
 }
 
@@ -41,6 +46,12 @@
     if (validTypes & CTA861_3) {
         FlattenableUtils::write(buffer, size, cta8613);
     }
+    if (validTypes & HDR10PLUS) {
+        size_t metadataSize = hdr10plus.size();
+        FlattenableUtils::write(buffer, size, metadataSize);
+        memcpy(buffer, hdr10plus.data(), metadataSize);
+        FlattenableUtils::advance(buffer, size, metadataSize);
+    }
 
     return NO_ERROR;
 }
@@ -62,6 +73,22 @@
         }
         FlattenableUtils::read(buffer, size, cta8613);
     }
+    if (validTypes & HDR10PLUS) {
+        if (size < sizeof(size_t)) {
+            return NO_MEMORY;
+        }
+
+        size_t metadataSize;
+        FlattenableUtils::read(buffer, size, metadataSize);
+
+        if (size < metadataSize) {
+            return NO_MEMORY;
+        }
+
+        hdr10plus.resize(metadataSize);
+        memcpy(hdr10plus.data(), buffer, metadataSize);
+        FlattenableUtils::advance(buffer, size, metadataSize);
+    }
 
     return NO_ERROR;
 }
@@ -91,6 +118,10 @@
         }
     }
 
+    if ((validTypes & HDR10PLUS) == HDR10PLUS) {
+        if (hdr10plus != rhs.hdr10plus) return false;
+    }
+
     return true;
 }
 
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0b37960..0e03b7d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -30,16 +30,21 @@
 #ifndef NO_BUFFERHUB
 #include <gui/BufferHubProducer.h>
 #endif
+
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
 #include <gui/BufferQueueDefs.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
 
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-
 namespace android {
 // ----------------------------------------------------------------------------
 
-using ::android::hardware::graphics::bufferqueue::V1_0::utils::
+using H2BGraphicBufferProducerV1_0 =
+        ::android::hardware::graphics::bufferqueue::V1_0::utils::
+        H2BGraphicBufferProducer;
+using H2BGraphicBufferProducerV2_0 =
+        ::android::hardware::graphics::bufferqueue::V2_0::utils::
         H2BGraphicBufferProducer;
 
 enum {
@@ -67,6 +72,7 @@
     GET_FRAME_TIMESTAMPS,
     GET_UNIQUE_ID,
     GET_CONSUMER_USAGE,
+    SET_LEGACY_BUFFER_DROP,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -190,10 +196,10 @@
 
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence) {
-        if (outBuffer == NULL) {
+        if (outBuffer == nullptr) {
             ALOGE("detachNextBuffer: outBuffer must not be NULL");
             return BAD_VALUE;
-        } else if (outFence == NULL) {
+        } else if (outFence == nullptr) {
             ALOGE("detachNextBuffer: outFence must not be NULL");
             return BAD_VALUE;
         }
@@ -301,7 +307,7 @@
             int api, bool producerControlledByApp, QueueBufferOutput* output) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        if (listener != NULL) {
+        if (listener != nullptr) {
             data.writeInt32(1);
             data.writeStrongBinder(IInterface::asBinder(listener));
         } else {
@@ -355,7 +361,7 @@
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
         data.writeUint64(usage);
-        status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, TF_ONE_WAY);
+        status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, IBinder::FLAG_ONEWAY);
         if (result != NO_ERROR) {
             ALOGE("allocateBuffers failed to transact: %d", result);
         }
@@ -432,6 +438,20 @@
         return reply.readInt32();
     }
 
+    virtual status_t setLegacyBufferDrop(bool drop) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(drop);
+        status_t result = remote()->transact(SET_LEGACY_BUFFER_DROP,
+                data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) override {
         Parcel data, reply;
@@ -534,9 +554,11 @@
 BpGraphicBufferProducer::~BpGraphicBufferProducer() {}
 
 class HpGraphicBufferProducer : public HpInterface<
-        BpGraphicBufferProducer, H2BGraphicBufferProducer> {
+        BpGraphicBufferProducer,
+        H2BGraphicBufferProducerV1_0,
+        H2BGraphicBufferProducerV2_0> {
 public:
-    HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
+    explicit HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
 
     status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
         return mBase->requestBuffer(slot, buf);
@@ -630,6 +652,10 @@
         return mBase->setDequeueTimeout(timeout);
     }
 
+    status_t setLegacyBufferDrop(bool drop) override {
+        return mBase->setLegacyBufferDrop(drop);
+    }
+
     status_t getLastQueuedBuffer(
             sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence,
@@ -651,11 +677,17 @@
     }
 };
 
-IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
+IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
         "android.gui.IGraphicBufferProducer");
 
 // ----------------------------------------------------------------------
 
+status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) {
+    // No-op for IGBP other than BufferQueue.
+    (void) drop;
+    return INVALID_OPERATION;
+}
+
 status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
     status_t res = OK;
     res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -738,8 +770,8 @@
             int bufferIdx   = data.readInt32();
             sp<GraphicBuffer> buffer;
             int result = requestBuffer(bufferIdx, &buffer);
-            reply->writeInt32(buffer != 0);
-            if (buffer != 0) {
+            reply->writeInt32(buffer != nullptr);
+            if (buffer != nullptr) {
                 reply->write(*buffer);
             }
             reply->writeInt32(result);
@@ -774,6 +806,10 @@
             int result = dequeueBuffer(&buf, &fence, width, height, format, usage, &bufferAge,
                                        getTimestamps ? &frameTimestamps : nullptr);
 
+            if (fence == nullptr) {
+                ALOGE("dequeueBuffer returned a NULL fence, setting to Fence::NO_FENCE");
+                fence = Fence::NO_FENCE;
+            }
             reply->writeInt32(buf);
             reply->write(*fence);
             reply->writeUint64(bufferAge);
@@ -797,12 +833,12 @@
             int32_t result = detachNextBuffer(&buffer, &fence);
             reply->writeInt32(result);
             if (result == NO_ERROR) {
-                reply->writeInt32(buffer != NULL);
-                if (buffer != NULL) {
+                reply->writeInt32(buffer != nullptr);
+                if (buffer != nullptr) {
                     reply->write(*buffer);
                 }
-                reply->writeInt32(fence != NULL);
-                if (fence != NULL) {
+                reply->writeInt32(fence != nullptr);
+                if (fence != nullptr) {
                     reply->write(*fence);
                 }
             }
@@ -956,6 +992,10 @@
                 ALOGE("getLastQueuedBuffer failed to write buffer: %d", result);
                 return result;
             }
+            if (fence == nullptr) {
+                ALOGE("getLastQueuedBuffer returned a NULL fence, setting to Fence::NO_FENCE");
+                fence = Fence::NO_FENCE;
+            }
             result = reply->write(*fence);
             if (result != NO_ERROR) {
                 ALOGE("getLastQueuedBuffer failed to write fence: %d", result);
@@ -1003,6 +1043,13 @@
             }
             return NO_ERROR;
         }
+        case SET_LEGACY_BUFFER_DROP: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            bool drop = data.readInt32();
+            int result = setLegacyBufferDrop(drop);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 62abfa8..936063a 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -15,7 +15,8 @@
  */
 
 #include <binder/Parcel.h>
-
+#include <gui/bufferqueue/1.0/H2BProducerListener.h>
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
 #include <gui/IProducerListener.h>
 
 namespace android {
@@ -61,7 +62,24 @@
 // translation unit (see clang warning -Wweak-vtables)
 BpProducerListener::~BpProducerListener() {}
 
-IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener")
+class HpProducerListener : public HpInterface<
+        BpProducerListener,
+        hardware::graphics::bufferqueue::V1_0::utils::H2BProducerListener,
+        hardware::graphics::bufferqueue::V2_0::utils::H2BProducerListener> {
+public:
+    explicit HpProducerListener(const sp<IBinder>& base) : PBase{base} {}
+
+    virtual void onBufferReleased() override {
+        mBase->onBufferReleased();
+    }
+
+    virtual bool needsReleaseNotify() override {
+        return mBase->needsReleaseNotify();
+    }
+};
+
+IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener,
+        "android.gui.IProducerListener")
 
 status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
         Parcel* reply, uint32_t flags) {
diff --git a/libs/gui/IRegionSamplingListener.cpp b/libs/gui/IRegionSamplingListener.cpp
new file mode 100644
index 0000000..40cbfce
--- /dev/null
+++ b/libs/gui/IRegionSamplingListener.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IRegionSamplingListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/IRegionSamplingListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_SAMPLE_COLLECTED = IBinder::FIRST_CALL_TRANSACTION,
+    LAST = ON_SAMPLE_COLLECTED,
+};
+
+} // Anonymous namespace
+
+class BpRegionSamplingListener : public SafeBpInterface<IRegionSamplingListener> {
+public:
+    explicit BpRegionSamplingListener(const sp<IBinder>& impl)
+          : SafeBpInterface<IRegionSamplingListener>(impl, "BpRegionSamplingListener") {}
+
+    ~BpRegionSamplingListener() override;
+
+    void onSampleCollected(float medianLuma) override {
+        callRemoteAsync<decltype(
+                &IRegionSamplingListener::onSampleCollected)>(Tag::ON_SAMPLE_COLLECTED, medianLuma);
+    }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpRegionSamplingListener::~BpRegionSamplingListener() = default;
+
+IMPLEMENT_META_INTERFACE(RegionSamplingListener, "android.gui.IRegionSamplingListener");
+
+status_t BnRegionSamplingListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                              uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_SAMPLE_COLLECTED:
+            return callLocalAsync(data, reply, &IRegionSamplingListener::onSampleCollected);
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index cec86e2..6c9d81a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -26,6 +26,7 @@
 
 #include <gui/IDisplayEventConnection.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/IRegionSamplingListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerDebugInfo.h>
@@ -63,21 +64,13 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual sp<ISurfaceComposerClient> createScopedConnection(
-            const sp<IGraphicBufferProducer>& parent)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(parent));
-        remote()->transact(BnSurfaceComposer::CREATE_SCOPED_CONNECTION, data, &reply);
-        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
-    }
-
-    virtual void setTransactionState(
-            const Vector<ComposerState>& state,
-            const Vector<DisplayState>& displays,
-            uint32_t flags)
-    {
+    virtual void setTransactionState(const Vector<ComposerState>& state,
+                                     const Vector<DisplayState>& displays, uint32_t flags,
+                                     const sp<IBinder>& applyToken,
+                                     const InputWindowCommands& commands,
+                                     int64_t desiredPresentTime,
+                                     const client_cache_t& uncacheBuffer,
+                                     const std::vector<ListenerCallbacks>& listenerCallbacks) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
 
@@ -92,6 +85,19 @@
         }
 
         data.writeUint32(flags);
+        data.writeStrongBinder(applyToken);
+        commands.write(data);
+        data.writeInt64(desiredPresentTime);
+        data.writeWeakBinder(uncacheBuffer.token);
+        data.writeUint64(uncacheBuffer.id);
+
+        if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+            for (const auto& [listener, callbackIds] : listenerCallbacks) {
+                data.writeStrongBinder(IInterface::asBinder(listener));
+                data.writeInt64Vector(callbackIds);
+            }
+        }
+
         remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
@@ -103,63 +109,94 @@
     }
 
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   bool& outCapturedSecureLayers,
-                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                                   int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
+                                   bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                                    ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
+        data.writeInt32(static_cast<int32_t>(reqDataspace));
+        data.writeInt32(static_cast<int32_t>(reqPixelFormat));
         data.write(sourceCrop);
         data.writeUint32(reqWidth);
         data.writeUint32(reqHeight);
-        data.writeInt32(minLayerZ);
-        data.writeInt32(maxLayerZ);
         data.writeInt32(static_cast<int32_t>(useIdentityTransform));
         data.writeInt32(static_cast<int32_t>(rotation));
         data.writeInt32(static_cast<int32_t>(captureSecureLayers));
-        status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
-
-        if (err != NO_ERROR) {
-            return err;
+        status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("captureScreen failed to transact: %d", result);
+            return result;
         }
-
-        err = reply.readInt32();
-        if (err != NO_ERROR) {
-            return err;
+        result = reply.readInt32();
+        if (result != NO_ERROR) {
+            ALOGE("captureScreen failed to readInt32: %d", result);
+            return result;
         }
 
         *outBuffer = new GraphicBuffer();
         reply.read(**outBuffer);
         outCapturedSecureLayers = reply.readBool();
 
-        return err;
+        return result;
     }
 
-    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
-                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
-                                   float frameScale, bool childrenOnly) {
+    virtual status_t captureScreen(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
+                                   sp<GraphicBuffer>* outBuffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeUint64(displayOrLayerStack);
+        status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN_BY_ID, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("captureScreen failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32();
+        if (result != NO_ERROR) {
+            ALOGE("captureScreen failed to readInt32: %d", result);
+            return result;
+        }
+
+        *outDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+        *outBuffer = new GraphicBuffer();
+        reply.read(**outBuffer);
+        return result;
+    }
+
+    virtual status_t captureLayers(
+            const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+            const Rect& sourceCrop,
+            const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeLayers, float frameScale,
+            bool childrenOnly) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(layerHandleBinder);
+        data.writeInt32(static_cast<int32_t>(reqDataspace));
+        data.writeInt32(static_cast<int32_t>(reqPixelFormat));
         data.write(sourceCrop);
+        data.writeInt32(excludeLayers.size());
+        for (auto el : excludeLayers) {
+            data.writeStrongBinder(el);
+        }
         data.writeFloat(frameScale);
         data.writeBool(childrenOnly);
-        status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
-
-        if (err != NO_ERROR) {
-            return err;
+        status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("captureLayers failed to transact: %d", result);
+            return result;
         }
-
-        err = reply.readInt32();
-        if (err != NO_ERROR) {
-            return err;
+        result = reply.readInt32();
+        if (result != NO_ERROR) {
+            ALOGE("captureLayers failed to readInt32: %d", result);
+            return result;
         }
 
         *outBuffer = new GraphicBuffer();
         reply.read(**outBuffer);
 
-        return err;
+        return result;
     }
 
     virtual bool authenticateSurfaceTexture(
@@ -281,12 +318,25 @@
         remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply);
     }
 
-    virtual sp<IBinder> getBuiltInDisplay(int32_t id)
-    {
+    virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeInt32(id);
-        remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
+        if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
+            NO_ERROR) {
+            std::vector<PhysicalDisplayId> displayIds;
+            if (reply.readUint64Vector(&displayIds) == NO_ERROR) {
+                return displayIds;
+            }
+        }
+
+        return {};
+    }
+
+    virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeUint64(displayId);
+        remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply);
         return reply.readStrongBinder();
     }
 
@@ -336,34 +386,6 @@
         return result;
     }
 
-    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
-        Parcel data, reply;
-        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result);
-            return result;
-        }
-        result = data.writeStrongBinder(display);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result);
-            return result;
-        }
-        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply);
-        if (result != NO_ERROR) {
-            ALOGE("getDisplayViewport failed to transact: %d", result);
-            return result;
-        }
-        result = reply.readInt32();
-        if (result == NO_ERROR) {
-            result = reply.read(*outViewport);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayViewport failed to read: %d", result);
-                return result;
-            }
-        }
-        return result;
-    }
-
     virtual int getActiveConfig(const sp<IBinder>& display)
     {
         Parcel data, reply;
@@ -376,10 +398,26 @@
     virtual status_t setActiveConfig(const sp<IBinder>& display, int id)
     {
         Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        data.writeStrongBinder(display);
-        data.writeInt32(id);
-        remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(display);
+        if (result != NO_ERROR) {
+            ALOGE("setActiveConfig failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = data.writeInt32(id);
+        if (result != NO_ERROR) {
+            ALOGE("setActiveConfig failed to writeInt32: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("setActiveConfig failed to transact: %d", result);
+            return result;
+        }
         return reply.readInt32();
     }
 
@@ -413,6 +451,32 @@
         return result;
     }
 
+    virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+            ui::DisplayPrimaries& primaries) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(display);
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getDisplayNativePrimaries failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32();
+        if (result == NO_ERROR) {
+            memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)),
+                    sizeof(ui::DisplayPrimaries));
+        }
+        return result;
+    }
+
     virtual ColorMode getActiveColorMode(const sp<IBinder>& display) {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -461,8 +525,16 @@
 
     virtual status_t clearAnimationFrameStats() {
         Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("clearAnimationFrameStats failed to transact: %d", result);
+            return result;
+        }
         return reply.readInt32();
     }
 
@@ -508,8 +580,8 @@
             ALOGE("enableVSyncInjections failed to writeBool: %d", result);
             return result;
         }
-        result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS,
-                data, &reply, TF_ONE_WAY);
+        result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply,
+                                    IBinder::FLAG_ONEWAY);
         if (result != NO_ERROR) {
             ALOGE("enableVSyncInjections failed to transact: %d", result);
             return result;
@@ -529,7 +601,8 @@
             ALOGE("injectVSync failed to writeInt64: %d", result);
             return result;
         }
-        result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, TF_ONE_WAY);
+        result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply,
+                                    IBinder::FLAG_ONEWAY);
         if (result != NO_ERROR) {
             ALOGE("injectVSync failed to transact: %d", result);
             return result;
@@ -567,6 +640,342 @@
         outLayers->clear();
         return reply.readParcelableVector(outLayers);
     }
+
+    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                              ui::PixelFormat* defaultPixelFormat,
+                                              ui::Dataspace* wideColorGamutDataspace,
+                                              ui::PixelFormat* wideColorGamutPixelFormat) const {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = static_cast<status_t>(reply.readInt32());
+        if (error == NO_ERROR) {
+            *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+            *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+            *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32());
+            *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+        }
+        return error;
+    }
+
+    virtual status_t getColorManagement(bool* outGetColorManagement) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply);
+        bool result;
+        status_t err = reply.readBool(&result);
+        if (err == NO_ERROR) {
+            *outGetColorManagement = result;
+        }
+        return err;
+    }
+
+    virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+                                                           ui::PixelFormat* outFormat,
+                                                           ui::Dataspace* outDataspace,
+                                                           uint8_t* outComponentMask) const {
+        if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE;
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display);
+
+        status_t error =
+                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+                                   data, &reply);
+        if (error != NO_ERROR) {
+            return error;
+        }
+
+        uint32_t value = 0;
+        error = reply.readUint32(&value);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        *outFormat = static_cast<ui::PixelFormat>(value);
+
+        error = reply.readUint32(&value);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        *outDataspace = static_cast<ui::Dataspace>(value);
+
+        error = reply.readUint32(&value);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        *outComponentMask = static_cast<uint8_t>(value);
+        return error;
+    }
+
+    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                      uint8_t componentMask,
+                                                      uint64_t maxFrames) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display);
+        data.writeBool(enable);
+        data.writeByte(static_cast<int8_t>(componentMask));
+        data.writeUint64(maxFrames);
+        status_t result =
+                remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data,
+                                   &reply);
+        return result;
+    }
+
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const {
+        if (!outStats) return BAD_VALUE;
+
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display);
+        data.writeUint64(maxFrames);
+        data.writeUint64(timestamp);
+
+        status_t result =
+                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply);
+
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        result = reply.readUint64(&outStats->numFrames);
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        result = reply.readUint64Vector(&outStats->component_0_sample);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readUint64Vector(&outStats->component_1_sample);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readUint64Vector(&outStats->component_2_sample);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readUint64Vector(&outStats->component_3_sample);
+        return result;
+    }
+
+    virtual status_t getProtectedContentSupport(bool* outSupported) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        status_t error =
+                remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = reply.readBool(outSupported);
+        return error;
+    }
+
+    virtual status_t isWideColorDisplay(const sp<IBinder>& token,
+                                        bool* outIsWideColorDisplay) const {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = data.writeStrongBinder(token);
+        if (error != NO_ERROR) {
+            return error;
+        }
+
+        error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = reply.readBool(outIsWideColorDisplay);
+        return error;
+    }
+
+    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+                                               const sp<IBinder>& stopLayerHandle,
+                                               const sp<IRegionSamplingListener>& listener) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write interface token");
+            return error;
+        }
+        error = data.write(samplingArea);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write sampling area");
+            return error;
+        }
+        error = data.writeStrongBinder(stopLayerHandle);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write stop layer handle");
+            return error;
+        }
+        error = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to write listener");
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("addRegionSamplingListener: Failed to transact");
+        }
+        return error;
+    }
+
+    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("removeRegionSamplingListener: Failed to write interface token");
+            return error;
+        }
+        error = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (error != NO_ERROR) {
+            ALOGE("removeRegionSamplingListener: Failed to write listener");
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
+                                   &reply);
+        if (error != NO_ERROR) {
+            ALOGE("removeRegionSamplingListener: Failed to transact");
+        }
+        return error;
+    }
+
+    virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              const std::vector<int32_t>& allowedConfigs) {
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(displayToken);
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = data.writeInt32Vector(allowedConfigs);
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("setAllowedDisplayConfigs failed to transact: %d", result);
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              std::vector<int32_t>* outAllowedConfigs) {
+        if (!outAllowedConfigs) return BAD_VALUE;
+        Parcel data, reply;
+        status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
+            return result;
+        }
+        result = data.writeStrongBinder(displayToken);
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
+            return result;
+        }
+        result = remote()->transact(BnSurfaceComposer::GET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to transact: %d", result);
+            return result;
+        }
+        result = reply.readInt32Vector(outAllowedConfigs);
+        if (result != NO_ERROR) {
+            ALOGE("getAllowedDisplayConfigs failed to readInt32Vector: %d", result);
+            return result;
+        }
+        return reply.readInt32();
+    }
+
+    virtual status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+                                                 bool* outSupport) const {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("getDisplayBrightnessSupport: failed to write interface token: %d", error);
+            return error;
+        }
+        error = data.writeStrongBinder(displayToken);
+        if (error != NO_ERROR) {
+            ALOGE("getDisplayBrightnessSupport: failed to write display token: %d", error);
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("getDisplayBrightnessSupport: failed to transact: %d", error);
+            return error;
+        }
+        bool support;
+        error = reply.readBool(&support);
+        if (error != NO_ERROR) {
+            ALOGE("getDisplayBrightnessSupport: failed to read support: %d", error);
+            return error;
+        }
+        *outSupport = support;
+        return NO_ERROR;
+    }
+
+    virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) const {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("setDisplayBrightness: failed to write interface token: %d", error);
+            return error;
+        }
+        error = data.writeStrongBinder(displayToken);
+        if (error != NO_ERROR) {
+            ALOGE("setDisplayBrightness: failed to write display token: %d", error);
+            return error;
+        }
+        error = data.writeFloat(brightness);
+        if (error != NO_ERROR) {
+            ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS, data, &reply);
+        if (error != NO_ERROR) {
+            ALOGE("setDisplayBrightness: failed to transact: %d", error);
+            return error;
+        }
+        return NO_ERROR;
+    }
+
+    virtual status_t notifyPowerHint(int32_t hintId) {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            ALOGE("notifyPowerHint: failed to write interface token: %d", error);
+            return error;
+        }
+        error = data.writeInt32(hintId);
+        if (error != NO_ERROR) {
+            ALOGE("notifyPowerHint: failed to write hintId: %d", error);
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_HINT, data, &reply,
+                                   IBinder::FLAG_ONEWAY);
+        if (error != NO_ERROR) {
+            ALOGE("notifyPowerHint: failed to transact: %d", error);
+            return error;
+        }
+        return NO_ERROR;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -587,14 +996,6 @@
             reply->writeStrongBinder(b);
             return NO_ERROR;
         }
-        case CREATE_SCOPED_CONNECTION: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IGraphicBufferProducer> bufferProducer =
-                interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
-            sp<IBinder> b = IInterface::asBinder(createScopedConnection(bufferProducer));
-            reply->writeStrongBinder(b);
-            return NO_ERROR;
-        }
         case SET_TRANSACTION_STATE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
@@ -602,10 +1003,10 @@
             if (count > data.dataSize()) {
                 return BAD_VALUE;
             }
-            ComposerState s;
             Vector<ComposerState> state;
             state.setCapacity(count);
             for (size_t i = 0; i < count; i++) {
+                ComposerState s;
                 if (s.read(data) == BAD_VALUE) {
                     return BAD_VALUE;
                 }
@@ -627,7 +1028,28 @@
             }
 
             uint32_t stateFlags = data.readUint32();
-            setTransactionState(state, displays, stateFlags);
+            sp<IBinder> applyToken = data.readStrongBinder();
+            InputWindowCommands inputWindowCommands;
+            inputWindowCommands.read(data);
+
+            int64_t desiredPresentTime = data.readInt64();
+
+            client_cache_t uncachedBuffer;
+            uncachedBuffer.token = data.readWeakBinder();
+            uncachedBuffer.id = data.readUint64();
+
+            std::vector<ListenerCallbacks> listenerCallbacks;
+            int32_t listenersSize = data.readInt32();
+            for (int32_t i = 0; i < listenersSize; i++) {
+                auto listener =
+                        interface_cast<ITransactionCompletedListener>(data.readStrongBinder());
+                std::vector<CallbackId> callbackIds;
+                data.readInt64Vector(&callbackIds);
+                listenerCallbacks.emplace_back(listener, callbackIds);
+            }
+
+            setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
+                                desiredPresentTime, uncachedBuffer, listenerCallbacks);
             return NO_ERROR;
         }
         case BOOT_FINISHED: {
@@ -638,21 +1060,23 @@
         case CAPTURE_SCREEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
+            ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+            ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
             sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             uint32_t reqWidth = data.readUint32();
             uint32_t reqHeight = data.readUint32();
-            int32_t minLayerZ = data.readInt32();
-            int32_t maxLayerZ = data.readInt32();
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
             bool captureSecureLayers = static_cast<bool>(data.readInt32());
 
             bool capturedSecureLayers = false;
-            status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, sourceCrop, reqWidth,
-                                         reqHeight, minLayerZ, maxLayerZ, useIdentityTransform,
-                                         static_cast<ISurfaceComposer::Rotation>(rotation), captureSecureLayers);
+            status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, reqDataspace,
+                                         reqPixelFormat, sourceCrop, reqWidth, reqHeight,
+                                         useIdentityTransform,
+                                         static_cast<ISurfaceComposer::Rotation>(rotation),
+                                         captureSecureLayers);
 
             reply->writeInt32(res);
             if (res == NO_ERROR) {
@@ -661,17 +1085,41 @@
             }
             return NO_ERROR;
         }
+        case CAPTURE_SCREEN_BY_ID: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            uint64_t displayOrLayerStack = data.readUint64();
+            ui::Dataspace outDataspace = ui::Dataspace::V0_SRGB;
+            sp<GraphicBuffer> outBuffer;
+            status_t res = captureScreen(displayOrLayerStack, &outDataspace, &outBuffer);
+            reply->writeInt32(res);
+            if (res == NO_ERROR) {
+                reply->writeInt32(static_cast<int32_t>(outDataspace));
+                reply->write(*outBuffer);
+            }
+            return NO_ERROR;
+        }
         case CAPTURE_LAYERS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> layerHandleBinder = data.readStrongBinder();
+            ui::Dataspace reqDataspace = static_cast<ui::Dataspace>(data.readInt32());
+            ui::PixelFormat reqPixelFormat = static_cast<ui::PixelFormat>(data.readInt32());
             sp<GraphicBuffer> outBuffer;
             Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
+
+            std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
+            int numExcludeHandles = data.readInt32();
+            excludeHandles.reserve(numExcludeHandles);
+            for (int i = 0; i < numExcludeHandles; i++) {
+                excludeHandles.emplace(data.readStrongBinder());
+            }
+
             float frameScale = data.readFloat();
             bool childrenOnly = data.readBool();
 
-            status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale,
-                                         childrenOnly);
+            status_t res =
+                    captureLayers(layerHandleBinder, &outBuffer, reqDataspace, reqPixelFormat,
+                                  sourceCrop, excludeHandles, frameScale, childrenOnly);
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
@@ -726,10 +1174,10 @@
             destroyDisplay(display);
             return NO_ERROR;
         }
-        case GET_BUILT_IN_DISPLAY: {
+        case GET_PHYSICAL_DISPLAY_TOKEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            int32_t id = data.readInt32();
-            sp<IBinder> display(getBuiltInDisplay(id));
+            PhysicalDisplayId displayId = data.readUint64();
+            sp<IBinder> display = getPhysicalDisplayToken(displayId);
             reply->writeStrongBinder(display);
             return NO_ERROR;
         }
@@ -760,26 +1208,6 @@
             }
             return NO_ERROR;
         }
-        case GET_DISPLAY_VIEWPORT: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Rect outViewport;
-            sp<IBinder> display = nullptr;
-            status_t result = data.readStrongBinder(&display);
-            if (result != NO_ERROR) {
-                ALOGE("getDisplayViewport failed to readStrongBinder: %d", result);
-                return result;
-            }
-            result = getDisplayViewport(display, &outViewport);
-            result = reply->writeInt32(result);
-            if (result == NO_ERROR) {
-                result = reply->write(outViewport);
-                if (result != NO_ERROR) {
-                    ALOGE("getDisplayViewport failed to write: %d", result);
-                    return result;
-                }
-            }
-            return NO_ERROR;
-        }
         case GET_ACTIVE_CONFIG: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
@@ -814,6 +1242,26 @@
             }
             return NO_ERROR;
         }
+        case GET_DISPLAY_NATIVE_PRIMARIES: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            ui::DisplayPrimaries primaries;
+            sp<IBinder> display = nullptr;
+
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result);
+                return result;
+            }
+
+            result = getDisplayNativePrimaries(display, primaries);
+            reply->writeInt32(result);
+            if (result == NO_ERROR) {
+                memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries,
+                        sizeof(ui::DisplayPrimaries));
+            }
+
+            return NO_ERROR;
+        }
         case GET_ACTIVE_COLOR_MODE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = nullptr;
@@ -914,12 +1362,235 @@
             }
             return result;
         }
+        case GET_COMPOSITION_PREFERENCE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            ui::Dataspace defaultDataspace;
+            ui::PixelFormat defaultPixelFormat;
+            ui::Dataspace wideColorGamutDataspace;
+            ui::PixelFormat wideColorGamutPixelFormat;
+            status_t error =
+                    getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+                                             &wideColorGamutDataspace, &wideColorGamutPixelFormat);
+            reply->writeInt32(error);
+            if (error == NO_ERROR) {
+                reply->writeInt32(static_cast<int32_t>(defaultDataspace));
+                reply->writeInt32(static_cast<int32_t>(defaultPixelFormat));
+                reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
+                reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat));
+            }
+            return error;
+        }
+        case GET_COLOR_MANAGEMENT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            bool result;
+            status_t error = getColorManagement(&result);
+            if (error == NO_ERROR) {
+                reply->writeBool(result);
+            }
+            return error;
+        }
+        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+            sp<IBinder> display = data.readStrongBinder();
+            ui::PixelFormat format;
+            ui::Dataspace dataspace;
+            uint8_t component = 0;
+            auto result =
+                    getDisplayedContentSamplingAttributes(display, &format, &dataspace, &component);
+            if (result == NO_ERROR) {
+                reply->writeUint32(static_cast<uint32_t>(format));
+                reply->writeUint32(static_cast<uint32_t>(dataspace));
+                reply->writeUint32(static_cast<uint32_t>(component));
+            }
+            return result;
+        }
+        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+            sp<IBinder> display = nullptr;
+            bool enable = false;
+            int8_t componentMask = 0;
+            uint64_t maxFrames = 0;
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d",
+                      result);
+                return result;
+            }
+
+            result = data.readBool(&enable);
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result);
+                return result;
+            }
+
+            result = data.readByte(static_cast<int8_t*>(&componentMask));
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d",
+                      result);
+                return result;
+            }
+
+            result = data.readUint64(&maxFrames);
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result);
+                return result;
+            }
+
+            return setDisplayContentSamplingEnabled(display, enable,
+                                                    static_cast<uint8_t>(componentMask), maxFrames);
+        }
+        case GET_DISPLAYED_CONTENT_SAMPLE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+            sp<IBinder> display = data.readStrongBinder();
+            uint64_t maxFrames = 0;
+            uint64_t timestamp = 0;
+
+            status_t result = data.readUint64(&maxFrames);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayedContentSample failure in reading max frames: %d", result);
+                return result;
+            }
+
+            result = data.readUint64(&timestamp);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result);
+                return result;
+            }
+
+            DisplayedFrameStats stats;
+            result = getDisplayedContentSample(display, maxFrames, timestamp, &stats);
+            if (result == NO_ERROR) {
+                reply->writeUint64(stats.numFrames);
+                reply->writeUint64Vector(stats.component_0_sample);
+                reply->writeUint64Vector(stats.component_1_sample);
+                reply->writeUint64Vector(stats.component_2_sample);
+                reply->writeUint64Vector(stats.component_3_sample);
+            }
+            return result;
+        }
+        case GET_PROTECTED_CONTENT_SUPPORT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            bool result;
+            status_t error = getProtectedContentSupport(&result);
+            if (error == NO_ERROR) {
+                reply->writeBool(result);
+            }
+            return error;
+        }
+        case IS_WIDE_COLOR_DISPLAY: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> display = nullptr;
+            status_t error = data.readStrongBinder(&display);
+            if (error != NO_ERROR) {
+                return error;
+            }
+            bool result;
+            error = isWideColorDisplay(display, &result);
+            if (error == NO_ERROR) {
+                reply->writeBool(result);
+            }
+            return error;
+        }
+        case GET_PHYSICAL_DISPLAY_IDS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            return reply->writeUint64Vector(getPhysicalDisplayIds());
+        }
+        case ADD_REGION_SAMPLING_LISTENER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            Rect samplingArea;
+            status_t result = data.read(samplingArea);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read sampling area");
+                return result;
+            }
+            sp<IBinder> stopLayerHandle;
+            result = data.readNullableStrongBinder(&stopLayerHandle);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read stop layer handle");
+                return result;
+            }
+            sp<IRegionSamplingListener> listener;
+            result = data.readNullableStrongBinder(&listener);
+            if (result != NO_ERROR) {
+                ALOGE("addRegionSamplingListener: Failed to read listener");
+                return result;
+            }
+            return addRegionSamplingListener(samplingArea, stopLayerHandle, listener);
+        }
+        case REMOVE_REGION_SAMPLING_LISTENER: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IRegionSamplingListener> listener;
+            status_t result = data.readNullableStrongBinder(&listener);
+            if (result != NO_ERROR) {
+                ALOGE("removeRegionSamplingListener: Failed to read listener");
+                return result;
+            }
+            return removeRegionSamplingListener(listener);
+        }
+        case SET_ALLOWED_DISPLAY_CONFIGS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> displayToken = data.readStrongBinder();
+            std::vector<int32_t> allowedConfigs;
+            data.readInt32Vector(&allowedConfigs);
+            status_t result = setAllowedDisplayConfigs(displayToken, allowedConfigs);
+            reply->writeInt32(result);
+            return result;
+        }
+        case GET_ALLOWED_DISPLAY_CONFIGS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> displayToken = data.readStrongBinder();
+            std::vector<int32_t> allowedConfigs;
+            status_t result = getAllowedDisplayConfigs(displayToken, &allowedConfigs);
+            reply->writeInt32Vector(allowedConfigs);
+            reply->writeInt32(result);
+            return result;
+        }
+        case GET_DISPLAY_BRIGHTNESS_SUPPORT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> displayToken;
+            status_t error = data.readNullableStrongBinder(&displayToken);
+            if (error != NO_ERROR) {
+                ALOGE("getDisplayBrightnessSupport: failed to read display token: %d", error);
+                return error;
+            }
+            bool support = false;
+            error = getDisplayBrightnessSupport(displayToken, &support);
+            reply->writeBool(support);
+            return error;
+        }
+        case SET_DISPLAY_BRIGHTNESS: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> displayToken;
+            status_t error = data.readNullableStrongBinder(&displayToken);
+            if (error != NO_ERROR) {
+                ALOGE("setDisplayBrightness: failed to read display token: %d", error);
+                return error;
+            }
+            float brightness = -1.0f;
+            error = data.readFloat(&brightness);
+            if (error != NO_ERROR) {
+                ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
+                return error;
+            }
+            return setDisplayBrightness(displayToken, brightness);
+        }
+        case NOTIFY_POWER_HINT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int32_t hintId;
+            status_t error = data.readInt32(&hintId);
+            if (error != NO_ERROR) {
+                ALOGE("notifyPowerHint: failed to read hintId: %d", error);
+                return error;
+            }
+            return notifyPowerHint(hintId);
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
     }
 }
 
-// ----------------------------------------------------------------------------
-
-};
+} // namespace android
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index a6890ee..129558b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -31,7 +31,7 @@
 
 enum class Tag : uint32_t {
     CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
-    DESTROY_SURFACE,
+    CREATE_WITH_SURFACE_PARENT,
     CLEAR_LAYER_FRAME_STATS,
     GET_LAYER_FRAME_STATS,
     LAST = GET_LAYER_FRAME_STATS,
@@ -47,19 +47,26 @@
     ~BpSurfaceComposerClient() override;
 
     status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
-                           uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
-                           int32_t ownerUid, sp<IBinder>* handle,
-                           sp<IGraphicBufferProducer>* gbp) override {
+                           uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata,
+                           sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) override {
         return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
                                                                             name, width, height,
                                                                             format, flags, parent,
-                                                                            windowType, ownerUid,
+                                                                            std::move(metadata),
                                                                             handle, gbp);
     }
 
-    status_t destroySurface(const sp<IBinder>& handle) override {
-        return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DESTROY_SURFACE,
-                                                                             handle);
+    status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height,
+                                     PixelFormat format, uint32_t flags,
+                                     const sp<IGraphicBufferProducer>& parent,
+                                     LayerMetadata metadata, sp<IBinder>* handle,
+                                     sp<IGraphicBufferProducer>* gbp) override {
+        return callRemote<decltype(
+                &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
+                                                                   name, width, height, format,
+                                                                   flags, parent,
+                                                                   std::move(metadata), handle,
+                                                                   gbp);
     }
 
     status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
@@ -92,8 +99,8 @@
     switch (tag) {
         case Tag::CREATE_SURFACE:
             return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
-        case Tag::DESTROY_SURFACE:
-            return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
+        case Tag::CREATE_WITH_SURFACE_PARENT:
+            return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent);
         case Tag::CLEAR_LAYER_FRAME_STATS:
             return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
         case Tag::GET_LAYER_FRAME_STATS:
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
new file mode 100644
index 0000000..74cd4f1
--- /dev/null
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ITransactionCompletedListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/ITransactionCompletedListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+    ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
+    LAST = ON_TRANSACTION_COMPLETED,
+};
+
+} // Anonymous namespace
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+    status_t err = output->writeStrongBinder(surfaceControl);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = output->writeInt64(acquireTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (previousReleaseFence) {
+        err = output->writeBool(true);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = output->write(*previousReleaseFence);
+    } else {
+        err = output->writeBool(false);
+    }
+    return err;
+}
+
+status_t SurfaceStats::readFromParcel(const Parcel* input) {
+    status_t err = input->readStrongBinder(&surfaceControl);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = input->readInt64(&acquireTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    bool hasFence = false;
+    err = input->readBool(&hasFence);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (hasFence) {
+        previousReleaseFence = new Fence();
+        err = input->read(*previousReleaseFence);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t TransactionStats::writeToParcel(Parcel* output) const {
+    status_t err = output->writeInt64Vector(callbackIds);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = output->writeInt64(latchTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (presentFence) {
+        err = output->writeBool(true);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = output->write(*presentFence);
+    } else {
+        err = output->writeBool(false);
+    }
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return output->writeParcelableVector(surfaceStats);
+}
+
+status_t TransactionStats::readFromParcel(const Parcel* input) {
+    status_t err = input->readInt64Vector(&callbackIds);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = input->readInt64(&latchTime);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    bool hasFence = false;
+    err = input->readBool(&hasFence);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (hasFence) {
+        presentFence = new Fence();
+        err = input->read(*presentFence);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return input->readParcelableVector(&surfaceStats);
+}
+
+status_t ListenerStats::writeToParcel(Parcel* output) const {
+    status_t err = output->writeInt32(static_cast<int32_t>(transactionStats.size()));
+    if (err != NO_ERROR) {
+        return err;
+    }
+    for (const auto& stats : transactionStats) {
+        err = output->writeParcelable(stats);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t ListenerStats::readFromParcel(const Parcel* input) {
+    int32_t transactionStats_size = input->readInt32();
+
+    for (int i = 0; i < transactionStats_size; i++) {
+        TransactionStats stats;
+        status_t err = input->readParcelable(&stats);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        transactionStats.push_back(stats);
+    }
+    return NO_ERROR;
+}
+
+ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener,
+                                         const std::unordered_set<CallbackId>& callbackIds) {
+    ListenerStats listenerStats;
+    listenerStats.listener = listener;
+    listenerStats.transactionStats.emplace_back(callbackIds);
+
+    return listenerStats;
+}
+
+class BpTransactionCompletedListener : public SafeBpInterface<ITransactionCompletedListener> {
+public:
+    explicit BpTransactionCompletedListener(const sp<IBinder>& impl)
+          : SafeBpInterface<ITransactionCompletedListener>(impl, "BpTransactionCompletedListener") {
+    }
+
+    ~BpTransactionCompletedListener() override;
+
+    void onTransactionCompleted(ListenerStats stats) override {
+        callRemoteAsync<decltype(&ITransactionCompletedListener::
+                                         onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
+                                                                  stats);
+    }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpTransactionCompletedListener::~BpTransactionCompletedListener() = default;
+
+IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener");
+
+status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data,
+                                                    Parcel* reply, uint32_t flags) {
+    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    auto tag = static_cast<Tag>(code);
+    switch (tag) {
+        case Tag::ON_TRANSACTION_COMPLETED:
+            return callLocalAsync(data, reply,
+                                  &ITransactionCompletedListener::onTransactionCompleted);
+    }
+}
+
+}; // namespace android
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index d3dc16d..cdde9a2 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -16,13 +16,14 @@
 
 #include <gui/LayerDebugInfo.h>
 
+#include <android-base/stringprintf.h>
+
 #include <ui/DebugUtils.h>
 
 #include <binder/Parcel.h>
 
-#include <utils/String8.h>
-
 using namespace android;
+using android::base::StringAppendF;
 
 #define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
 
@@ -42,7 +43,6 @@
     RETURN_ON_ERROR(parcel->writeInt32(mWidth));
     RETURN_ON_ERROR(parcel->writeInt32(mHeight));
     RETURN_ON_ERROR(parcel->write(mCrop));
-    RETURN_ON_ERROR(parcel->write(mFinalCrop));
     RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
     RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
     RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
@@ -81,7 +81,6 @@
     RETURN_ON_ERROR(parcel->readInt32(&mWidth));
     RETURN_ON_ERROR(parcel->readInt32(&mHeight));
     RETURN_ON_ERROR(parcel->read(mCrop));
-    RETURN_ON_ERROR(parcel->read(mFinalCrop));
     mColor.r = parcel->readFloat();
     RETURN_ON_ERROR(parcel->errorCheck());
     mColor.g = parcel->readFloat();
@@ -110,39 +109,37 @@
 }
 
 std::string to_string(const LayerDebugInfo& info) {
-    String8 result;
+    std::string result;
 
-    result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
+    StringAppendF(&result, "+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
     info.mTransparentRegion.dump(result, "TransparentRegion");
     info.mVisibleRegion.dump(result, "VisibleRegion");
     info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
 
-    result.appendFormat("      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
-            info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
-            info.mWidth, info.mHeight);
+    StringAppendF(&result, "      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
+                  info.mLayerStack, info.mZ, static_cast<double>(info.mX),
+                  static_cast<double>(info.mY), info.mWidth, info.mHeight);
 
-    result.appendFormat("crop=%s, finalCrop=%s, ",
-            to_string(info.mCrop).c_str(), to_string(info.mFinalCrop).c_str());
-    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("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]));
+    StringAppendF(&result, "crop=%s, ", to_string(info.mCrop).c_str());
+    StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
+    StringAppendF(&result, "dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
+    StringAppendF(&result, "pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
+    StringAppendF(&result, "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);
+    StringAppendF(&result, "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]));
     result.append("\n");
-    result.appendFormat("      parent=%s\n", info.mParentName.c_str());
-    result.appendFormat("      activeBuffer=[%4ux%4u:%4u,%s],",
-            info.mActiveBufferWidth, info.mActiveBufferHeight,
-            info.mActiveBufferStride,
-            decodePixelFormat(info.mActiveBufferFormat).c_str());
-    result.appendFormat(" queued-frames=%d, mRefreshPending=%d",
-            info.mNumQueuedFrames, info.mRefreshPending);
+    StringAppendF(&result, "      parent=%s\n", info.mParentName.c_str());
+    StringAppendF(&result, "      activeBuffer=[%4ux%4u:%4u,%s],", info.mActiveBufferWidth,
+                  info.mActiveBufferHeight, info.mActiveBufferStride,
+                  decodePixelFormat(info.mActiveBufferFormat).c_str());
+    StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", info.mNumQueuedFrames,
+                  info.mRefreshPending);
     result.append("\n");
-    return std::string(result.c_str());
+    return result;
 }
 
 } // android
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
new file mode 100644
index 0000000..04d2871
--- /dev/null
+++ b/libs/gui/LayerMetadata.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
+#include <gui/LayerMetadata.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+LayerMetadata::LayerMetadata() = default;
+
+LayerMetadata::LayerMetadata(std::unordered_map<uint32_t, std::vector<uint8_t>> map)
+      : mMap(std::move(map)) {}
+
+LayerMetadata::LayerMetadata(const LayerMetadata& other) = default;
+
+LayerMetadata::LayerMetadata(LayerMetadata&& other) = default;
+
+bool LayerMetadata::merge(const LayerMetadata& other, bool eraseEmpty) {
+    bool changed = false;
+    for (const auto& entry : other.mMap) {
+        auto it = mMap.find(entry.first);
+        if (it != mMap.cend() && it->second != entry.second) {
+            if (eraseEmpty && entry.second.empty()) {
+                mMap.erase(it);
+            } else {
+                it->second = entry.second;
+            }
+            changed = true;
+        } else if (it == mMap.cend() && !entry.second.empty()) {
+            mMap[entry.first] = entry.second;
+            changed = true;
+        }
+    }
+    return changed;
+}
+
+status_t LayerMetadata::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32(static_cast<int>(mMap.size()));
+    status_t status = OK;
+    for (const auto& entry : mMap) {
+        status = parcel->writeUint32(entry.first);
+        if (status != OK) {
+            break;
+        }
+        status = parcel->writeByteVector(entry.second);
+        if (status != OK) {
+            break;
+        }
+    }
+    return status;
+}
+
+status_t LayerMetadata::readFromParcel(const Parcel* parcel) {
+    int size = parcel->readInt32();
+    status_t status = OK;
+    mMap.clear();
+    for (int i = 0; i < size; ++i) {
+        uint32_t key = parcel->readUint32();
+        status = parcel->readByteVector(&mMap[key]);
+        if (status != OK) {
+            break;
+        }
+    }
+    return status;
+}
+
+LayerMetadata& LayerMetadata::operator=(const LayerMetadata& other) {
+    mMap = other.mMap;
+    return *this;
+}
+
+LayerMetadata& LayerMetadata::operator=(LayerMetadata&& other) {
+    mMap = std::move(other.mMap);
+    return *this;
+}
+
+bool LayerMetadata::has(uint32_t key) const {
+    return mMap.count(key);
+}
+
+int32_t LayerMetadata::getInt32(uint32_t key, int32_t fallback) const {
+    if (!has(key)) return fallback;
+    const std::vector<uint8_t>& data = mMap.at(key);
+    if (data.size() < sizeof(uint32_t)) return fallback;
+    Parcel p;
+    p.setData(data.data(), data.size());
+    return p.readInt32();
+}
+
+void LayerMetadata::setInt32(uint32_t key, int32_t value) {
+    std::vector<uint8_t>& data = mMap[key];
+    Parcel p;
+    p.writeInt32(value);
+    data.resize(p.dataSize());
+    memcpy(data.data(), p.data(), p.dataSize());
+}
+
+std::string LayerMetadata::itemToString(uint32_t key, const char* separator) const {
+    if (!has(key)) return std::string();
+    switch (key) {
+        case METADATA_OWNER_UID:
+            return StringPrintf("ownerUID%s%d", separator, getInt32(key, 0));
+        case METADATA_WINDOW_TYPE:
+            return StringPrintf("windowType%s%d", separator, getInt32(key, 0));
+        case METADATA_TASK_ID:
+            return StringPrintf("taskId%s%d", separator, getInt32(key, 0));
+        default:
+            return StringPrintf("%d%s%dbytes", key, separator,
+                                static_cast<int>(mMap.at(key).size()));
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 01acc2d..6066421 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "LayerState"
+
+#include <inttypes.h>
+
 #include <utils/Errors.h>
 #include <binder/Parcel.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -25,7 +29,7 @@
 status_t layer_state_t::write(Parcel& output) const
 {
     output.writeStrongBinder(surface);
-    output.writeUint32(what);
+    output.writeUint64(what);
     output.writeFloat(x);
     output.writeFloat(y);
     output.writeInt32(z);
@@ -37,26 +41,67 @@
     output.writeUint32(mask);
     *reinterpret_cast<layer_state_t::matrix22_t *>(
             output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
-    output.write(crop);
-    output.write(finalCrop);
-    output.writeStrongBinder(barrierHandle);
+    output.write(crop_legacy);
+    output.writeStrongBinder(barrierHandle_legacy);
     output.writeStrongBinder(reparentHandle);
-    output.writeUint64(frameNumber);
+    output.writeUint64(frameNumber_legacy);
     output.writeInt32(overrideScalingMode);
-    output.writeStrongBinder(IInterface::asBinder(barrierGbp));
+    output.writeStrongBinder(IInterface::asBinder(barrierGbp_legacy));
     output.writeStrongBinder(relativeLayerHandle);
     output.writeStrongBinder(parentHandleForChild);
     output.writeFloat(color.r);
     output.writeFloat(color.g);
     output.writeFloat(color.b);
+#ifndef NO_INPUT
+    inputInfo.write(output);
+#endif
     output.write(transparentRegion);
+    output.writeUint32(transform);
+    output.writeBool(transformToDisplayInverse);
+    output.write(crop);
+    output.write(frame);
+    if (buffer) {
+        output.writeBool(true);
+        output.write(*buffer);
+    } else {
+        output.writeBool(false);
+    }
+    if (acquireFence) {
+        output.writeBool(true);
+        output.write(*acquireFence);
+    } else {
+        output.writeBool(false);
+    }
+    output.writeUint32(static_cast<uint32_t>(dataspace));
+    output.write(hdrMetadata);
+    output.write(surfaceDamageRegion);
+    output.writeInt32(api);
+    if (sidebandStream) {
+        output.writeBool(true);
+        output.writeNativeHandle(sidebandStream->handle());
+    } else {
+        output.writeBool(false);
+    }
+
+    memcpy(output.writeInplace(16 * sizeof(float)),
+           colorTransform.asArray(), 16 * sizeof(float));
+    output.writeFloat(cornerRadius);
+    output.writeBool(hasListenerCallbacks);
+    output.writeWeakBinder(cachedBuffer.token);
+    output.writeUint64(cachedBuffer.id);
+    output.writeParcelable(metadata);
+
+    output.writeFloat(bgColorAlpha);
+    output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
+    output.writeBool(colorSpaceAgnostic);
+
     return NO_ERROR;
 }
 
 status_t layer_state_t::read(const Parcel& input)
 {
     surface = input.readStrongBinder();
-    what = input.readUint32();
+    what = input.readUint64();
     x = input.readFloat();
     y = input.readFloat();
     z = input.readInt32();
@@ -72,20 +117,54 @@
     } else {
         return BAD_VALUE;
     }
-    input.read(crop);
-    input.read(finalCrop);
-    barrierHandle = input.readStrongBinder();
+    input.read(crop_legacy);
+    barrierHandle_legacy = input.readStrongBinder();
     reparentHandle = input.readStrongBinder();
-    frameNumber = input.readUint64();
+    frameNumber_legacy = input.readUint64();
     overrideScalingMode = input.readInt32();
-    barrierGbp =
-        interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
+    barrierGbp_legacy = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     relativeLayerHandle = input.readStrongBinder();
     parentHandleForChild = input.readStrongBinder();
     color.r = input.readFloat();
     color.g = input.readFloat();
     color.b = input.readFloat();
+
+#ifndef NO_INPUT
+    inputInfo = InputWindowInfo::read(input);
+#endif
+
     input.read(transparentRegion);
+    transform = input.readUint32();
+    transformToDisplayInverse = input.readBool();
+    input.read(crop);
+    input.read(frame);
+    buffer = new GraphicBuffer();
+    if (input.readBool()) {
+        input.read(*buffer);
+    }
+    acquireFence = new Fence();
+    if (input.readBool()) {
+        input.read(*acquireFence);
+    }
+    dataspace = static_cast<ui::Dataspace>(input.readUint32());
+    input.read(hdrMetadata);
+    input.read(surfaceDamageRegion);
+    api = input.readInt32();
+    if (input.readBool()) {
+        sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
+    }
+
+    colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+    cornerRadius = input.readFloat();
+    hasListenerCallbacks = input.readBool();
+    cachedBuffer.token = input.readWeakBinder();
+    cachedBuffer.id = input.readUint64();
+    input.readParcelable(&metadata);
+
+    bgColorAlpha = input.readFloat();
+    bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+    colorSpaceAgnostic = input.readBool();
+
     return NO_ERROR;
 }
 
@@ -166,6 +245,7 @@
     }
     if (other.what & eLayerChanged) {
         what |= eLayerChanged;
+        what &= ~eRelativeLayerChanged;
         z = other.z;
     }
     if (other.what & eSizeChanged) {
@@ -194,19 +274,19 @@
         what |= eLayerStackChanged;
         layerStack = other.layerStack;
     }
-    if (other.what & eCropChanged) {
-        what |= eCropChanged;
-        crop = other.crop;
+    if (other.what & eCropChanged_legacy) {
+        what |= eCropChanged_legacy;
+        crop_legacy = other.crop_legacy;
     }
-    if (other.what & eDeferTransaction) {
-        what |= eDeferTransaction;
-        barrierHandle = other.barrierHandle;
-        barrierGbp = other.barrierGbp;
-        frameNumber = other.frameNumber;
+    if (other.what & eCornerRadiusChanged) {
+        what |= eCornerRadiusChanged;
+        cornerRadius = other.cornerRadius;
     }
-    if (other.what & eFinalCropChanged) {
-        what |= eFinalCropChanged;
-        finalCrop = other.finalCrop;
+    if (other.what & eDeferTransaction_legacy) {
+        what |= eDeferTransaction_legacy;
+        barrierHandle_legacy = other.barrierHandle_legacy;
+        barrierGbp_legacy = other.barrierGbp_legacy;
+        frameNumber_legacy = other.frameNumber_legacy;
     }
     if (other.what & eOverrideScalingModeChanged) {
         what |= eOverrideScalingModeChanged;
@@ -224,6 +304,7 @@
     }
     if (other.what & eRelativeLayerChanged) {
         what |= eRelativeLayerChanged;
+        what &= ~eLayerChanged;
         z = other.z;
         relativeLayerHandle = other.relativeLayerHandle;
     }
@@ -234,6 +315,124 @@
     if (other.what & eDestroySurface) {
         what |= eDestroySurface;
     }
+    if (other.what & eTransformChanged) {
+        what |= eTransformChanged;
+        transform = other.transform;
+    }
+    if (other.what & eTransformToDisplayInverseChanged) {
+        what |= eTransformToDisplayInverseChanged;
+        transformToDisplayInverse = other.transformToDisplayInverse;
+    }
+    if (other.what & eCropChanged) {
+        what |= eCropChanged;
+        crop = other.crop;
+    }
+    if (other.what & eFrameChanged) {
+        what |= eFrameChanged;
+        frame = other.frame;
+    }
+    if (other.what & eBufferChanged) {
+        what |= eBufferChanged;
+        buffer = other.buffer;
+    }
+    if (other.what & eAcquireFenceChanged) {
+        what |= eAcquireFenceChanged;
+        acquireFence = other.acquireFence;
+    }
+    if (other.what & eDataspaceChanged) {
+        what |= eDataspaceChanged;
+        dataspace = other.dataspace;
+    }
+    if (other.what & eHdrMetadataChanged) {
+        what |= eHdrMetadataChanged;
+        hdrMetadata = other.hdrMetadata;
+    }
+    if (other.what & eSurfaceDamageRegionChanged) {
+        what |= eSurfaceDamageRegionChanged;
+        surfaceDamageRegion = other.surfaceDamageRegion;
+    }
+    if (other.what & eApiChanged) {
+        what |= eApiChanged;
+        api = other.api;
+    }
+    if (other.what & eSidebandStreamChanged) {
+        what |= eSidebandStreamChanged;
+        sidebandStream = other.sidebandStream;
+    }
+    if (other.what & eColorTransformChanged) {
+        what |= eColorTransformChanged;
+        colorTransform = other.colorTransform;
+    }
+    if (other.what & eHasListenerCallbacksChanged) {
+        what |= eHasListenerCallbacksChanged;
+        hasListenerCallbacks = other.hasListenerCallbacks;
+    }
+
+#ifndef NO_INPUT
+    if (other.what & eInputInfoChanged) {
+        what |= eInputInfoChanged;
+        inputInfo = other.inputInfo;
+    }
+#endif
+
+    if (other.what & eCachedBufferChanged) {
+        what |= eCachedBufferChanged;
+        cachedBuffer = other.cachedBuffer;
+    }
+    if (other.what & eBackgroundColorChanged) {
+        what |= eBackgroundColorChanged;
+        color = other.color;
+        bgColorAlpha = other.bgColorAlpha;
+        bgColorDataspace = other.bgColorDataspace;
+    }
+    if (other.what & eMetadataChanged) {
+        what |= eMetadataChanged;
+        metadata.merge(other.metadata);
+    }
+    if ((other.what & what) != other.what) {
+        ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
+              "other.what=0x%" PRIu64 " what=0x%" PRIu64,
+              other.what, what);
+    }
+}
+
+// ------------------------------- InputWindowCommands ----------------------------------------
+
+void InputWindowCommands::merge(const InputWindowCommands& other) {
+    transferTouchFocusCommands
+            .insert(transferTouchFocusCommands.end(),
+                    std::make_move_iterator(other.transferTouchFocusCommands.begin()),
+                    std::make_move_iterator(other.transferTouchFocusCommands.end()));
+
+    syncInputWindows |= other.syncInputWindows;
+}
+
+void InputWindowCommands::clear() {
+    transferTouchFocusCommands.clear();
+    syncInputWindows = false;
+}
+
+void InputWindowCommands::write(Parcel& output) const {
+    output.writeUint32(static_cast<uint32_t>(transferTouchFocusCommands.size()));
+    for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) {
+        output.writeStrongBinder(transferTouchFocusCommand.fromToken);
+        output.writeStrongBinder(transferTouchFocusCommand.toToken);
+    }
+
+    output.writeBool(syncInputWindows);
+}
+
+void InputWindowCommands::read(const Parcel& input) {
+    size_t count = input.readUint32();
+    transferTouchFocusCommands.clear();
+    for (size_t i = 0; i < count; i++) {
+        TransferTouchFocusCommand transferTouchFocusCommand;
+        transferTouchFocusCommand.fromToken = input.readStrongBinder();
+        transferTouchFocusCommand.toToken = input.readStrongBinder();
+        transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
+    }
+
+    syncInputWindows = input.readBool();
 }
 
 }; // namespace android
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
new file mode 100644
index 0000000..73150dc
--- /dev/null
+++ b/libs/gui/OWNERS
@@ -0,0 +1,7 @@
+jessehall@google.com
+jwcai@google.com
+lpy@google.com
+marissaw@google.com
+mathias@google.com
+racarr@google.com
+stoza@google.com
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 52c9067..2f8e104 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -38,11 +38,11 @@
 status_t StreamSplitter::createSplitter(
         const sp<IGraphicBufferConsumer>& inputQueue,
         sp<StreamSplitter>* outSplitter) {
-    if (inputQueue == NULL) {
+    if (inputQueue == nullptr) {
         ALOGE("createSplitter: inputQueue must not be NULL");
         return BAD_VALUE;
     }
-    if (outSplitter == NULL) {
+    if (outSplitter == nullptr) {
         ALOGE("createSplitter: outSplitter must not be NULL");
         return BAD_VALUE;
     }
@@ -74,7 +74,7 @@
 
 status_t StreamSplitter::addOutput(
         const sp<IGraphicBufferProducer>& outputQueue) {
-    if (outputQueue == NULL) {
+    if (outputQueue == nullptr) {
         ALOGE("addOutput: outputQueue must not be NULL");
         return BAD_VALUE;
     }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 2de14c8..e6eb327 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -20,6 +20,11 @@
 
 #include <gui/Surface.h>
 
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+
 #include <inttypes.h>
 
 #include <android/native_window.h>
@@ -39,9 +44,6 @@
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
 namespace android {
 
 using ui::ColorMode;
@@ -156,7 +158,7 @@
     ATRACE_CALL();
 
     DisplayStatInfo stats;
-    status_t result = composerService()->getDisplayStats(NULL, &stats);
+    status_t result = composerService()->getDisplayStats(nullptr, &stats);
     if (result != NO_ERROR) {
         return result;
     }
@@ -321,48 +323,27 @@
     return NO_ERROR;
 }
 
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-
 status_t Surface::getWideColorSupport(bool* supported) {
     ATRACE_CALL();
 
-    sp<IBinder> display(
-        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    Vector<ColorMode> colorModes;
-    status_t err =
-        composerService()->getDisplayColorModes(display, &colorModes);
-
-    if (err)
-        return err;
-
-    bool wideColorBoardConfig =
-        getBool<ISurfaceFlingerConfigs,
-                &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
-
-    *supported = false;
-    for (ColorMode colorMode : colorModes) {
-        switch (colorMode) {
-            case ColorMode::DISPLAY_P3:
-            case ColorMode::ADOBE_RGB:
-            case ColorMode::DCI_P3:
-                if (wideColorBoardConfig) {
-                    *supported = true;
-                }
-                break;
-            default:
-                break;
-        }
+    const sp<IBinder> display = composerService()->getInternalDisplayToken();
+    if (display == nullptr) {
+        return NAME_NOT_FOUND;
     }
 
-    return NO_ERROR;
+    *supported = false;
+    status_t error = composerService()->isWideColorDisplay(display, supported);
+    return error;
 }
 
 status_t Surface::getHdrSupport(bool* supported) {
     ATRACE_CALL();
 
-    sp<IBinder> display(
-        composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+    const sp<IBinder> display = composerService()->getInternalDisplayToken();
+    if (display == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+
     HdrCapabilities hdrCapabilities;
     status_t err =
         composerService()->getHdrCapabilities(display, &hdrCapabilities);
@@ -474,6 +455,82 @@
     return NO_ERROR;
 }
 
+class FenceMonitor {
+public:
+    explicit FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) {
+        std::thread thread(&FenceMonitor::loop, this);
+        pthread_setname_np(thread.native_handle(), mName);
+        thread.detach();
+    }
+
+    void queueFence(const sp<Fence>& fence) {
+        char message[64];
+
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
+            snprintf(message, sizeof(message), "%s fence %u has signaled", mName, mFencesQueued);
+            ATRACE_NAME(message);
+            // Need an increment on both to make the trace number correct.
+            mFencesQueued++;
+            mFencesSignaled++;
+            return;
+        }
+        snprintf(message, sizeof(message), "Trace %s fence %u", mName, mFencesQueued);
+        ATRACE_NAME(message);
+
+        mQueue.push_back(fence);
+        mCondition.notify_one();
+        mFencesQueued++;
+        ATRACE_INT(mName, int32_t(mQueue.size()));
+    }
+
+private:
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+    void loop() {
+        while (true) {
+            threadLoop();
+        }
+    }
+#pragma clang diagnostic pop
+
+    void threadLoop() {
+        sp<Fence> fence;
+        uint32_t fenceNum;
+        {
+            std::unique_lock<std::mutex> lock(mMutex);
+            while (mQueue.empty()) {
+                mCondition.wait(lock);
+            }
+            fence = mQueue[0];
+            fenceNum = mFencesSignaled;
+        }
+        {
+            char message[64];
+            snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum);
+            ATRACE_NAME(message);
+
+            status_t result = fence->waitForever(message);
+            if (result != OK) {
+                ALOGE("Error waiting for fence: %d", result);
+            }
+        }
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mQueue.pop_front();
+            mFencesSignaled++;
+            ATRACE_INT(mName, int32_t(mQueue.size()));
+        }
+    }
+
+    const char* mName;
+    uint32_t mFencesQueued;
+    uint32_t mFencesSignaled;
+    std::deque<sp<Fence>> mQueue;
+    std::condition_variable mCondition;
+    std::mutex mMutex;
+};
+
 int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
     ATRACE_CALL();
     ALOGV("Surface::dequeueBuffer");
@@ -501,7 +558,7 @@
         if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
                 BufferItem::INVALID_BUFFER_SLOT) {
             sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
-            if (gbuf != NULL) {
+            if (gbuf != nullptr) {
                 *buffer = gbuf.get();
                 *fenceFd = -1;
                 return OK;
@@ -541,7 +598,12 @@
     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
 
     // this should never happen
-    ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+    ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+
+    if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
+        static FenceMonitor hwcReleaseThread("HWC release");
+        hwcReleaseThread.queueFence(fence);
+    }
 
     if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
         freeAllBuffers();
@@ -619,7 +681,7 @@
 int Surface::getSlotFromBufferLocked(
         android_native_buffer_t* buffer) const {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i].buffer != NULL &&
+        if (mSlots[i].buffer != nullptr &&
                 mSlots[i].buffer->handle == buffer->handle) {
             return i;
         }
@@ -754,7 +816,7 @@
         // The consumer doesn't send it back to prevent us from having two
         // file descriptors of the same fence.
         mFrameEventHistory->updateAcquireFence(mNextFrameNumber,
-                std::make_shared<FenceTime>(std::move(fence)));
+                std::make_shared<FenceTime>(fence));
 
         // Cache timestamps of signaled fences so we can close their file
         // descriptors.
@@ -767,8 +829,9 @@
     mDefaultHeight = output.height;
     mNextFrameNumber = output.nextFrameNumber;
 
-    // Disable transform hint if sticky transform is set.
-    if (mStickyTransform == 0) {
+    // Ignore transform hint if sticky transform is set or transform to display inverse flag is
+    // set.
+    if (mStickyTransform == 0 && !transformToDisplayInverse()) {
         mTransformHint = output.transformHint;
     }
 
@@ -785,6 +848,11 @@
 
     mQueueBufferCondition.broadcast();
 
+    if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
+        static FenceMonitor gpuCompletionThread("GPU completion");
+        gpuCompletionThread.queueFence(fence);
+    }
+
     return err;
 }
 
@@ -965,6 +1033,9 @@
     case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA:
         res = dispatchSetBuffersCta8613Metadata(args);
         break;
+    case NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA:
+        res = dispatchSetBuffersHdr10PlusMetadata(args);
+        break;
     case NATIVE_WINDOW_SET_SURFACE_DAMAGE:
         res = dispatchSetSurfaceDamage(args);
         break;
@@ -1120,6 +1191,12 @@
     return setBuffersCta8613Metadata(metadata);
 }
 
+int Surface::dispatchSetBuffersHdr10PlusMetadata(va_list args) {
+    const size_t size = va_arg(args, size_t);
+    const uint8_t* metadata = va_arg(args, const uint8_t*);
+    return setBuffersHdr10PlusMetadata(size, metadata);
+}
+
 int Surface::dispatchSetSurfaceDamage(va_list args) {
     android_native_rect_t* rects = va_arg(args, android_native_rect_t*);
     size_t numRects = va_arg(args, size_t);
@@ -1195,6 +1272,11 @@
     return getConsumerUsage(usage);
 }
 
+bool Surface::transformToDisplayInverse() {
+    return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
+            NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+}
+
 int Surface::connect(int api) {
     static sp<IProducerListener> listener = new DummyProducerListener();
     return connect(api, listener);
@@ -1217,8 +1299,10 @@
         mDefaultHeight = output.height;
         mNextFrameNumber = output.nextFrameNumber;
 
-        // Disable transform hint if sticky transform is set.
-        if (mStickyTransform == 0) {
+        // Ignore transform hint if sticky transform is set or transform to display inverse flag is
+        // set. Transform hint should be ignored if the client is expected to always submit buffers
+        // in the same orientation.
+        if (mStickyTransform == 0 && !transformToDisplayInverse()) {
             mTransformHint = output.transformHint;
         }
 
@@ -1268,7 +1352,7 @@
     ATRACE_CALL();
     ALOGV("Surface::detachNextBuffer");
 
-    if (outBuffer == NULL || outFence == NULL) {
+    if (outBuffer == nullptr || outFence == nullptr) {
         return BAD_VALUE;
     }
 
@@ -1277,8 +1361,8 @@
         mRemovedBuffers.clear();
     }
 
-    sp<GraphicBuffer> buffer(NULL);
-    sp<Fence> fence(NULL);
+    sp<GraphicBuffer> buffer(nullptr);
+    sp<Fence> fence(nullptr);
     status_t result = mGraphicBufferProducer->detachNextBuffer(
             &buffer, &fence);
     if (result != NO_ERROR) {
@@ -1286,19 +1370,19 @@
     }
 
     *outBuffer = buffer;
-    if (fence != NULL && fence->isValid()) {
+    if (fence != nullptr && fence->isValid()) {
         *outFence = fence;
     } else {
         *outFence = Fence::NO_FENCE;
     }
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i].buffer != NULL &&
+        if (mSlots[i].buffer != nullptr &&
                 mSlots[i].buffer->getId() == buffer->getId()) {
             if (mReportRemovedBuffers) {
                 mRemovedBuffers.push_back(mSlots[i].buffer);
             }
-            mSlots[i].buffer = NULL;
+            mSlots[i].buffer = nullptr;
         }
     }
 
@@ -1349,7 +1433,7 @@
     ATRACE_CALL();
 
     Rect realRect(Rect::EMPTY_RECT);
-    if (rect == NULL || rect->isEmpty()) {
+    if (rect == nullptr || rect->isEmpty()) {
         realRect.clear();
     } else {
         realRect = *rect;
@@ -1515,6 +1599,13 @@
     ATRACE_CALL();
     ALOGV("Surface::setBuffersTransform");
     Mutex::Autolock lock(mMutex);
+    // Ensure NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY is sticky. If the client sets the flag, do not
+    // override it until the surface is disconnected. This is a temporary workaround for camera
+    // until they switch to using Buffer State Layers. Currently if client sets the buffer transform
+    // it may be overriden by the buffer producer when the producer sets the buffer transform.
+    if (transformToDisplayInverse()) {
+        transform |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+    }
     mTransform = transform;
     return NO_ERROR;
 }
@@ -1568,6 +1659,19 @@
     return NO_ERROR;
 }
 
+int Surface::setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata) {
+    ALOGV("Surface::setBuffersBlobMetadata");
+    Mutex::Autolock lock(mMutex);
+    if (size > 0) {
+        mHdrMetadata.hdr10plus.assign(metadata, metadata + size);
+        mHdrMetadata.validTypes |= HdrMetadata::HDR10PLUS;
+    } else {
+        mHdrMetadata.validTypes &= ~HdrMetadata::HDR10PLUS;
+        mHdrMetadata.hdr10plus.clear();
+    }
+    return NO_ERROR;
+}
+
 Dataspace Surface::getBuffersDataSpace() {
     ALOGV("Surface::getBuffersDataSpace");
     Mutex::Autolock lock(mMutex);
@@ -1576,7 +1680,7 @@
 
 void Surface::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i].buffer = 0;
+        mSlots[i].buffer = nullptr;
     }
 }
 
@@ -1616,12 +1720,12 @@
     // src and dst with, height and format must be identical. no verification
     // is done here.
     status_t err;
-    uint8_t* src_bits = NULL;
+    uint8_t* src_bits = nullptr;
     err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(),
             reinterpret_cast<void**>(&src_bits));
     ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
 
-    uint8_t* dst_bits = NULL;
+    uint8_t* dst_bits = nullptr;
     err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
             reinterpret_cast<void**>(&dst_bits), *dstFenceFd);
     ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
@@ -1669,7 +1773,7 @@
 status_t Surface::lock(
         ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
 {
-    if (mLockedBuffer != 0) {
+    if (mLockedBuffer != nullptr) {
         ALOGE("Surface::lock failed, already locked");
         return INVALID_OPERATION;
     }
@@ -1701,7 +1805,7 @@
 
         // figure out if we can copy the frontbuffer back
         const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
-        const bool canCopyBack = (frontBuffer != 0 &&
+        const bool canCopyBack = (frontBuffer != nullptr &&
                 backBuffer->width  == frontBuffer->width &&
                 backBuffer->height == frontBuffer->height &&
                 backBuffer->format == frontBuffer->format);
@@ -1763,7 +1867,7 @@
 
 status_t Surface::unlockAndPost()
 {
-    if (mLockedBuffer == 0) {
+    if (mLockedBuffer == nullptr) {
         ALOGE("Surface::unlockAndPost failed, no locked buffer");
         return INVALID_OPERATION;
     }
@@ -1777,7 +1881,7 @@
             mLockedBuffer->handle, strerror(-err));
 
     mPostedBuffer = mLockedBuffer;
-    mLockedBuffer = 0;
+    mLockedBuffer = nullptr;
     return err;
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1002576..def9fe9 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -25,7 +25,9 @@
 #include <utils/String8.h>
 #include <utils/threads.h>
 
+#include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 
 #include <system/graphics.h>
 
@@ -40,8 +42,15 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
+#ifndef NO_INPUT
+#include <input/InputWindow.h>
+#endif
+
 #include <private/gui/ComposerService.h>
 
+// This server size should always be smaller than the server cache size
+#define BUFFER_CACHE_MAX_SIZE 64
+
 namespace android {
 
 using ui::ColorMode;
@@ -60,7 +69,7 @@
     while (getService(name, &mComposerService) != NO_ERROR) {
         usleep(250000);
     }
-    assert(mComposerService != NULL);
+    assert(mComposerService != nullptr);
 
     // Create the death listener.
     class DeathObserver : public IBinder::DeathRecipient {
@@ -81,9 +90,9 @@
 /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
     ComposerService& instance = ComposerService::getInstance();
     Mutex::Autolock _l(instance.mLock);
-    if (instance.mComposerService == NULL) {
+    if (instance.mComposerService == nullptr) {
         ComposerService::getInstance().connectLocked();
-        assert(instance.mComposerService != NULL);
+        assert(instance.mComposerService != nullptr);
         ALOGD("ComposerService reconnected");
     }
     return instance.mComposerService;
@@ -92,19 +101,231 @@
 void ComposerService::composerServiceDied()
 {
     Mutex::Autolock _l(mLock);
-    mComposerService = NULL;
-    mDeathObserver = NULL;
+    mComposerService = nullptr;
+    mDeathObserver = nullptr;
+}
+
+class DefaultComposerClient: public Singleton<DefaultComposerClient> {
+    Mutex mLock;
+    sp<SurfaceComposerClient> mClient;
+    friend class Singleton<ComposerService>;
+public:
+    static sp<SurfaceComposerClient> getComposerClient() {
+        DefaultComposerClient& dc = DefaultComposerClient::getInstance();
+        Mutex::Autolock _l(dc.mLock);
+        if (dc.mClient == nullptr) {
+            dc.mClient = new SurfaceComposerClient;
+        }
+        return dc.mClient;
+    }
+};
+ANDROID_SINGLETON_STATIC_INSTANCE(DefaultComposerClient);
+
+
+sp<SurfaceComposerClient> SurfaceComposerClient::getDefault() {
+    return DefaultComposerClient::getComposerClient();
 }
 
 // ---------------------------------------------------------------------------
 
-SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
-    mForceSynchronous(other.mForceSynchronous),
-    mTransactionNestCount(other.mTransactionNestCount),
-    mAnimation(other.mAnimation),
-    mEarlyWakeup(other.mEarlyWakeup) {
+// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
+// to be able to return a sp<> to its instance to pass to SurfaceFlinger.
+// ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance.
+
+// 0 is an invalid callback id
+TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
+
+CallbackId TransactionCompletedListener::getNextIdLocked() {
+    return mCallbackIdCounter++;
+}
+
+sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+    static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+    return sInstance;
+}
+
+sp<ITransactionCompletedListener> TransactionCompletedListener::getIInstance() {
+    return static_cast<sp<ITransactionCompletedListener>>(getInstance());
+}
+
+void TransactionCompletedListener::startListeningLocked() {
+    if (mListening) {
+        return;
+    }
+    ProcessState::self()->startThreadPool();
+    mListening = true;
+}
+
+CallbackId TransactionCompletedListener::addCallbackFunction(
+        const TransactionCompletedCallback& callbackFunction,
+        const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
+                surfaceControls) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    startListeningLocked();
+
+    CallbackId callbackId = getNextIdLocked();
+    mCallbacks[callbackId].callbackFunction = callbackFunction;
+
+    auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls;
+
+    for (const auto& surfaceControl : surfaceControls) {
+        callbackSurfaceControls[surfaceControl->getHandle()] = surfaceControl;
+    }
+
+    return callbackId;
+}
+
+void TransactionCompletedListener::addSurfaceControlToCallbacks(
+        const sp<SurfaceControl>& surfaceControl,
+        const std::unordered_set<CallbackId>& callbackIds) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    for (auto callbackId : callbackIds) {
+        mCallbacks[callbackId].surfaceControls.emplace(std::piecewise_construct,
+                                                       std::forward_as_tuple(
+                                                               surfaceControl->getHandle()),
+                                                       std::forward_as_tuple(surfaceControl));
+    }
+}
+
+void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    /* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered
+     * callbackIds, except for when Transactions are merged together. This probably cannot be
+     * solved before this point because the Transactions could be merged together and applied in a
+     * different process.
+     *
+     * Fortunately, we get all the callbacks for this listener for the same frame together at the
+     * same time. This means if any Transactions were merged together, we will get their callbacks
+     * at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps for all the
+     * callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
+     * that could possibly exist for the callbacks.
+     */
+    std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+    for (const auto& transactionStats : listenerStats.transactionStats) {
+        for (auto callbackId : transactionStats.callbackIds) {
+            auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
+            surfaceControls.insert(callbackSurfaceControls.begin(), callbackSurfaceControls.end());
+        }
+    }
+
+    for (const auto& transactionStats : listenerStats.transactionStats) {
+        for (auto callbackId : transactionStats.callbackIds) {
+            auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
+            if (!callbackFunction) {
+                ALOGE("cannot call null callback function, skipping");
+                continue;
+            }
+            std::vector<SurfaceControlStats> surfaceControlStats;
+            for (const auto& surfaceStats : transactionStats.surfaceStats) {
+                surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl],
+                                                 surfaceStats.acquireTime,
+                                                 surfaceStats.previousReleaseFence);
+            }
+
+            callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
+                             surfaceControlStats);
+            mCallbacks.erase(callbackId);
+        }
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId);
+
+class BufferCache : public Singleton<BufferCache> {
+public:
+    BufferCache() : token(new BBinder()) {}
+
+    sp<IBinder> getToken() {
+        return IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    }
+
+    status_t getCacheId(const sp<GraphicBuffer>& buffer, uint64_t* cacheId) {
+        std::lock_guard<std::mutex> lock(mMutex);
+
+        auto itr = mBuffers.find(buffer->getId());
+        if (itr == mBuffers.end()) {
+            return BAD_VALUE;
+        }
+        itr->second = getCounter();
+        *cacheId = buffer->getId();
+        return NO_ERROR;
+    }
+
+    uint64_t cache(const sp<GraphicBuffer>& buffer) {
+        std::lock_guard<std::mutex> lock(mMutex);
+
+        if (mBuffers.size() >= BUFFER_CACHE_MAX_SIZE) {
+            evictLeastRecentlyUsedBuffer();
+        }
+
+        buffer->addDeathCallback(bufferCacheCallback, nullptr);
+
+        mBuffers[buffer->getId()] = getCounter();
+        return buffer->getId();
+    }
+
+    void uncache(uint64_t cacheId) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        uncacheLocked(cacheId);
+    }
+
+    void uncacheLocked(uint64_t cacheId) REQUIRES(mMutex) {
+        mBuffers.erase(cacheId);
+        SurfaceComposerClient::doUncacheBufferTransaction(cacheId);
+    }
+
+private:
+    void evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
+        auto itr = mBuffers.begin();
+        uint64_t minCounter = itr->second;
+        auto minBuffer = itr;
+        itr++;
+
+        while (itr != mBuffers.end()) {
+            uint64_t counter = itr->second;
+            if (counter < minCounter) {
+                minCounter = counter;
+                minBuffer = itr;
+            }
+            itr++;
+        }
+        uncacheLocked(minBuffer->first);
+    }
+
+    uint64_t getCounter() REQUIRES(mMutex) {
+        static uint64_t counter = 0;
+        return counter++;
+    }
+
+    std::mutex mMutex;
+    std::map<uint64_t /*Cache id*/, uint64_t /*counter*/> mBuffers GUARDED_BY(mMutex);
+
+    // Used by ISurfaceComposer to identify which process is sending the cached buffer.
+    sp<IBinder> token;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) {
+    // GraphicBuffer id's are used as the cache ids.
+    BufferCache::getInstance().uncache(graphicBufferId);
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
+      : mForceSynchronous(other.mForceSynchronous),
+        mTransactionNestCount(other.mTransactionNestCount),
+        mAnimation(other.mAnimation),
+        mEarlyWakeup(other.mEarlyWakeup),
+        mDesiredPresentTime(other.mDesiredPresentTime) {
     mDisplayStates = other.mDisplayStates;
     mComposerStates = other.mComposerStates;
+    mInputWindowCommands = other.mInputWindowCommands;
 }
 
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
@@ -127,9 +348,96 @@
     }
     other.mDisplayStates.clear();
 
+    for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
+        auto& [callbackIds, surfaceControls] = callbackInfo;
+        mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
+                                                                callbackIds.begin()),
+                                                        std::make_move_iterator(callbackIds.end()));
+        mListenerCallbacks[listener]
+                .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
+                                        std::make_move_iterator(surfaceControls.end()));
+    }
+    other.mListenerCallbacks.clear();
+
+    mInputWindowCommands.merge(other.mInputWindowCommands);
+    other.mInputWindowCommands.clear();
+
+    mContainsBuffer = other.mContainsBuffer;
+    other.mContainsBuffer = false;
+
+    mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
+    other.mEarlyWakeup = false;
+
     return *this;
 }
 
+void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
+        const sp<ISurfaceComposerClient>& client) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    Vector<ComposerState> composerStates;
+    Vector<DisplayState> displayStates;
+
+    ComposerState s;
+    s.client = client;
+    s.state.surface = handle;
+    s.state.what |= layer_state_t::eReparent;
+    s.state.parentHandleForChild = nullptr;
+
+    composerStates.add(s);
+    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, {});
+}
+
+void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+    client_cache_t uncacheBuffer;
+    uncacheBuffer.token = BufferCache::getInstance().getToken();
+    uncacheBuffer.id = cacheId;
+
+    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, {});
+}
+
+void SurfaceComposerClient::Transaction::cacheBuffers() {
+    if (!mContainsBuffer) {
+        return;
+    }
+
+    size_t count = 0;
+    for (auto& [sc, cs] : mComposerStates) {
+        layer_state_t* s = getLayerState(sc);
+        if (!(s->what & layer_state_t::eBufferChanged)) {
+            continue;
+        }
+
+        // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste
+        // time trying to cache them.
+        if (!s->buffer) {
+            continue;
+        }
+
+        uint64_t cacheId = 0;
+        status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
+        if (ret == NO_ERROR) {
+            s->what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged);
+            s->buffer = nullptr;
+        } else {
+            cacheId = BufferCache::getInstance().cache(s->buffer);
+        }
+        s->what |= layer_state_t::eCachedBufferChanged;
+        s->cachedBuffer.token = BufferCache::getInstance().getToken();
+        s->cachedBuffer.id = cacheId;
+
+        // If we have more buffers than the size of the cache, we should stop caching so we don't
+        // evict other buffers in this transaction
+        count++;
+        if (count >= BUFFER_CACHE_MAX_SIZE) {
+            break;
+        }
+    }
+}
+
 status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
     if (mStatus != NO_ERROR) {
         return mStatus;
@@ -137,6 +445,32 @@
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
+    std::vector<ListenerCallbacks> listenerCallbacks;
+
+    // For every listener with registered callbacks
+    for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
+        auto& [callbackIds, surfaceControls] = callbackInfo;
+        if (callbackIds.empty()) {
+            continue;
+        }
+
+        listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+
+        // If the listener has any SurfaceControls set on this Transaction update the surface state
+        for (const auto& surfaceControl : surfaceControls) {
+            layer_state_t* s = getLayerState(surfaceControl);
+            if (!s) {
+                ALOGE("failed to get layer state");
+                continue;
+            }
+            s->what |= layer_state_t::eHasListenerCallbacksChanged;
+            s->hasListenerCallbacks = true;
+        }
+    }
+    mListenerCallbacks.clear();
+
+    cacheBuffers();
+
     Vector<ComposerState> composerStates;
     Vector<DisplayState> displayStates;
     uint32_t flags = 0;
@@ -166,7 +500,12 @@
     mAnimation = false;
     mEarlyWakeup = false;
 
-    sf->setTransactionState(composerStates, displayStates, flags);
+    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
+                            mDesiredPresentTime,
+                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
+                            listenerCallbacks);
+    mInputWindowCommands.clear();
     mStatus = NO_ERROR;
     return NO_ERROR;
 }
@@ -182,8 +521,20 @@
     return ComposerService::getComposerService()->destroyDisplay(display);
 }
 
-sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
-    return ComposerService::getComposerService()->getBuiltInDisplay(id);
+std::vector<PhysicalDisplayId> SurfaceComposerClient::getPhysicalDisplayIds() {
+    return ComposerService::getComposerService()->getPhysicalDisplayIds();
+}
+
+std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
+    return ComposerService::getComposerService()->getInternalDisplayId();
+}
+
+sp<IBinder> SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) {
+    return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId);
+}
+
+sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
+    return ComposerService::getComposerService()->getInternalDisplayToken();
 }
 
 void SurfaceComposerClient::Transaction::setAnimationTransaction() {
@@ -206,6 +557,15 @@
     return &(mComposerStates[sc].state);
 }
 
+void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
+        const sp<SurfaceControl>& sc) {
+    auto& callbackInfo = mListenerCallbacks[TransactionCompletedListener::getIInstance()];
+    callbackInfo.surfaceControls.insert(sc);
+
+    TransactionCompletedListener::getInstance()
+            ->addSurfaceControlToCallbacks(sc, callbackInfo.callbackIds);
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
         const sp<SurfaceControl>& sc, float x, float y) {
     layer_state_t* s = getLayerState(sc);
@@ -216,6 +576,8 @@
     s->what |= layer_state_t::ePositionChanged;
     s->x = x;
     s->y = y;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -240,9 +602,7 @@
     s->w = w;
     s->h = h;
 
-    // Resizing a surface makes the transaction synchronous.
-    mForceSynchronous = true;
-
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -254,7 +614,10 @@
         return *this;
     }
     s->what |= layer_state_t::eLayerChanged;
+    s->what &= ~layer_state_t::eRelativeLayerChanged;
     s->z = z;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -265,8 +628,11 @@
         mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eRelativeLayerChanged;
+    s->what &= ~layer_state_t::eLayerChanged;
     s->relativeLayerHandle = relativeTo;
     s->z = z;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -286,6 +652,8 @@
     s->flags &= ~mask;
     s->flags |= (flags & mask);
     s->mask |= mask;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -299,6 +667,8 @@
     }
     s->what |= layer_state_t::eTransparentRegionChanged;
     s->transparentRegion = transparentRegion;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -311,6 +681,8 @@
     }
     s->what |= layer_state_t::eAlphaChanged;
     s->alpha = alpha;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -323,6 +695,22 @@
     }
     s->what |= layer_state_t::eLayerStackChanged;
     s->layerStack = layerStack;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMetadata(
+        const sp<SurfaceControl>& sc, uint32_t key, std::vector<uint8_t> data) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eMetadataChanged;
+    s->metadata.mMap[key] = std::move(data);
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -341,57 +729,68 @@
     matrix.dsdy = dsdy;
     matrix.dtdy = dtdy;
     s->matrix = matrix;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop_legacy(
         const sp<SurfaceControl>& sc, const Rect& crop) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eCropChanged;
-    s->crop = crop;
+    s->what |= layer_state_t::eCropChanged_legacy;
+    s->crop_legacy = crop;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCornerRadius(
+        const sp<SurfaceControl>& sc, float cornerRadius) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eFinalCropChanged;
-    s->finalCrop = crop;
+    s->what |= layer_state_t::eCornerRadiusChanged;
+    s->cornerRadius = cornerRadius;
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
-        const sp<SurfaceControl>& sc,
-        const sp<IBinder>& handle, uint64_t frameNumber) {
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                                 const sp<IBinder>& handle,
+                                                                 uint64_t frameNumber) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eDeferTransaction;
-    s->barrierHandle = handle;
-    s->frameNumber = frameNumber;
+    s->what |= layer_state_t::eDeferTransaction_legacy;
+    s->barrierHandle_legacy = handle;
+    s->frameNumber_legacy = frameNumber;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
-        const sp<SurfaceControl>& sc,
-        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                                 const sp<Surface>& barrierSurface,
+                                                                 uint64_t frameNumber) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eDeferTransaction;
-    s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
-    s->frameNumber = frameNumber;
+    s->what |= layer_state_t::eDeferTransaction_legacy;
+    s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
+    s->frameNumber_legacy = frameNumber;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -405,6 +804,8 @@
     }
     s->what |= layer_state_t::eReparentChildren;
     s->reparentHandle = newParentHandle;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -418,6 +819,8 @@
     }
     s->what |= layer_state_t::eReparent;
     s->parentHandleForChild = newParentHandle;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -431,6 +834,219 @@
     }
     s->what |= layer_state_t::eColorChanged;
     s->color = color;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundColor(
+        const sp<SurfaceControl>& sc, const half3& color, float alpha, ui::Dataspace dataspace) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eBackgroundColorChanged;
+    s->color = color;
+    s->bgColorAlpha = alpha;
+    s->bgColorDataspace = dataspace;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransform(
+        const sp<SurfaceControl>& sc, uint32_t transform) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eTransformChanged;
+    s->transform = transform;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
+                                                                 bool transformToDisplayInverse) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eTransformToDisplayInverseChanged;
+    s->transformToDisplayInverse = transformToDisplayInverse;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+        const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eCropChanged;
+    s->crop = crop;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame(
+        const sp<SurfaceControl>& sc, const Rect& frame) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eFrameChanged;
+    s->frame = frame;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
+        const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eBufferChanged;
+    s->buffer = buffer;
+
+    registerSurfaceControlForCallback(sc);
+
+    mContainsBuffer = true;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
+        const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eAcquireFenceChanged;
+    s->acquireFence = fence;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace(
+        const sp<SurfaceControl>& sc, ui::Dataspace dataspace) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDataspaceChanged;
+    s->dataspace = dataspace;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata(
+        const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eHdrMetadataChanged;
+    s->hdrMetadata = hdrMetadata;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSurfaceDamageRegion(
+        const sp<SurfaceControl>& sc, const Region& surfaceDamageRegion) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eSurfaceDamageRegionChanged;
+    s->surfaceDamageRegion = surfaceDamageRegion;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApi(
+        const sp<SurfaceControl>& sc, int32_t api) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eApiChanged;
+    s->api = api;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSidebandStream(
+        const sp<SurfaceControl>& sc, const sp<NativeHandle>& sidebandStream) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eSidebandStreamChanged;
+    s->sidebandStream = sidebandStream;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime(
+        nsecs_t desiredPresentTime) {
+    mDesiredPresentTime = desiredPresentTime;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorSpaceAgnostic(
+        const sp<SurfaceControl>& sc, const bool agnostic) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorSpaceAgnosticChanged;
+    s->colorSpaceAgnostic = agnostic;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+        TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+    auto listener = TransactionCompletedListener::getInstance();
+
+    auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,
+                                         std::placeholders::_2, std::placeholders::_3);
+    const auto& surfaceControls =
+            mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls;
+
+    CallbackId callbackId = listener->addCallbackFunction(callbackWithContext, surfaceControls);
+
+    mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
+            callbackId);
     return *this;
 }
 
@@ -441,6 +1057,8 @@
         mStatus = BAD_INDEX;
     }
     s->what |= layer_state_t::eDetachChildren;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -468,6 +1086,8 @@
 
     s->what |= layer_state_t::eOverrideScalingModeChanged;
     s->overrideScalingMode = overrideScalingMode;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
@@ -479,17 +1099,104 @@
         return *this;
     }
     s->what |= layer_state_t::eGeometryAppliesWithResize;
+
+    registerSurfaceControlForCallback(sc);
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface(
-        const sp<SurfaceControl>& sc) {
+#ifndef NO_INPUT
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
+        const sp<SurfaceControl>& sc,
+        const InputWindowInfo& info) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eDestroySurface;
+    s->inputInfo = info;
+    s->what |= layer_state_t::eInputInfoChanged;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus(
+        const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+    InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand;
+    transferTouchFocusCommand.fromToken = fromToken;
+    transferTouchFocusCommand.toToken = toToken;
+    mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
+    mInputWindowCommands.syncInputWindows = true;
+    return *this;
+}
+
+#endif
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
+    const sp<SurfaceControl>& sc, const mat3& matrix, const vec3& translation) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eColorTransformChanged;
+    s->colorTransform = mat4(matrix, translation);
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometry(
+        const sp<SurfaceControl>& sc, const Rect& source, const Rect& dst, int transform) {
+    setCrop_legacy(sc, source);
+
+    int x = dst.left;
+    int y = dst.top;
+
+    float sourceWidth = source.getWidth();
+    float sourceHeight = source.getHeight();
+
+    float xScale = sourceWidth < 0 ? 1.0f : dst.getWidth() / sourceWidth;
+    float yScale = sourceHeight < 0 ? 1.0f : dst.getHeight() / sourceHeight;
+    float matrix[4] = {1, 0, 0, 1};
+
+    switch (transform) {
+        case NATIVE_WINDOW_TRANSFORM_FLIP_H:
+            matrix[0] = -xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = yScale;
+            x += source.getWidth();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_FLIP_V:
+            matrix[0] = xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = -yScale;
+            y += source.getHeight();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_ROT_90:
+            matrix[0] = 0; matrix[1] = -yScale;
+            matrix[2] = xScale; matrix[3] = 0;
+            x += source.getHeight();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_ROT_180:
+            matrix[0] = -xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = -yScale;
+            x += source.getWidth();
+            y += source.getHeight();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_ROT_270:
+            matrix[0] = 0; matrix[1] = yScale;
+            matrix[2] = -xScale; matrix[3] = 0;
+            y += source.getWidth();
+            break;
+        default:
+            matrix[0] = xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = yScale;
+            break;
+    }
+    setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]);
+    setPosition(sc, x, y);
+
     return *this;
 }
 
@@ -559,11 +1266,6 @@
 {
 }
 
-SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
-    : mStatus(NO_INIT), mParent(root)
-{
-}
-
 SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
     : mStatus(NO_ERROR), mClient(client)
 {
@@ -571,12 +1273,10 @@
 
 void SurfaceComposerClient::onFirstRef() {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (sf != 0 && mStatus == NO_INIT) {
-        auto rootProducer = mParent.promote();
+    if (sf != nullptr && mStatus == NO_INIT) {
         sp<ISurfaceComposerClient> conn;
-        conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
-                sf->createConnection();
-        if (conn != 0) {
+        conn = sf->createConnection();
+        if (conn != nullptr) {
             mClient = conn;
             mStatus = NO_ERROR;
         }
@@ -606,39 +1306,49 @@
     // this can be called more than once.
     sp<ISurfaceComposerClient> client;
     Mutex::Autolock _lm(mLock);
-    if (mClient != 0) {
+    if (mClient != nullptr) {
         client = mClient; // hold ref while lock is held
         mClient.clear();
     }
     mStatus = NO_INIT;
 }
 
-sp<SurfaceControl> SurfaceComposerClient::createSurface(
-        const String8& name,
-        uint32_t w,
-        uint32_t h,
-        PixelFormat format,
-        uint32_t flags,
-        SurfaceControl* parent,
-        int32_t windowType,
-        int32_t ownerUid)
-{
+sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
+                                                        PixelFormat format, uint32_t flags,
+                                                        SurfaceControl* parent,
+                                                        LayerMetadata metadata) {
     sp<SurfaceControl> s;
-    createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid);
+    createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata));
     return s;
 }
 
-status_t SurfaceComposerClient::createSurfaceChecked(
-        const String8& name,
-        uint32_t w,
-        uint32_t h,
-        PixelFormat format,
-        sp<SurfaceControl>* outSurface,
-        uint32_t flags,
-        SurfaceControl* parent,
-        int32_t windowType,
-        int32_t ownerUid)
-{
+sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w,
+                                                                  uint32_t h, PixelFormat format,
+                                                                  uint32_t flags, Surface* parent,
+                                                                  LayerMetadata metadata) {
+    sp<SurfaceControl> sur;
+    status_t err = mStatus;
+
+    if (mStatus == NO_ERROR) {
+        sp<IBinder> handle;
+        sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer();
+        sp<IGraphicBufferProducer> gbp;
+
+        err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp,
+                                               std::move(metadata), &handle, &gbp);
+        ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
+        if (err == NO_ERROR) {
+            return new SurfaceControl(this, handle, gbp, true /* owned */);
+        }
+    }
+    return nullptr;
+}
+
+status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
+                                                     PixelFormat format,
+                                                     sp<SurfaceControl>* outSurface, uint32_t flags,
+                                                     SurfaceControl* parent,
+                                                     LayerMetadata metadata) {
     sp<SurfaceControl> sur;
     status_t err = mStatus;
 
@@ -650,8 +1360,9 @@
         if (parent != nullptr) {
             parentHandle = parent->getHandle();
         }
-        err = mClient->createSurface(name, w, h, format, flags, parentHandle,
-                windowType, ownerUid, &handle, &gbp);
+
+        err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
+                                     &handle, &gbp);
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
             *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
@@ -660,13 +1371,6 @@
     return err;
 }
 
-status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
-    if (mStatus != NO_ERROR)
-        return mStatus;
-    status_t err = mClient->destroySurface(sid);
-    return err;
-}
-
 status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
     if (mStatus != NO_ERROR) {
         return mStatus;
@@ -718,10 +1422,6 @@
     return NO_ERROR;
 }
 
-status_t SurfaceComposerClient::getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) {
-    return ComposerService::getComposerService()->getDisplayViewport(display, outViewport);
-}
-
 int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveConfig(display);
 }
@@ -730,11 +1430,28 @@
     return ComposerService::getComposerService()->setActiveConfig(display, id);
 }
 
+status_t SurfaceComposerClient::setAllowedDisplayConfigs(
+        const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) {
+    return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken,
+                                                                           allowedConfigs);
+}
+
+status_t SurfaceComposerClient::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                                         std::vector<int32_t>* outAllowedConfigs) {
+    return ComposerService::getComposerService()->getAllowedDisplayConfigs(displayToken,
+                                                                           outAllowedConfigs);
+}
+
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
         Vector<ColorMode>* outColorModes) {
     return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
 }
 
+status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display,
+        ui::DisplayPrimaries& outPrimaries) {
+    return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries);
+}
+
 ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
     return ComposerService::getComposerService()->getActiveColorMode(display);
 }
@@ -749,6 +1466,20 @@
     ComposerService::getComposerService()->setPowerMode(token, mode);
 }
 
+status_t SurfaceComposerClient::getCompositionPreference(
+        ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat,
+        ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) {
+    return ComposerService::getComposerService()
+            ->getCompositionPreference(defaultDataspace, defaultPixelFormat,
+                                       wideColorGamutDataspace, wideColorGamutPixelFormat);
+}
+
+bool SurfaceComposerClient::getProtectedContentSupport() {
+    bool supported = false;
+    ComposerService::getComposerService()->getProtectedContentSupport(&supported);
+    return supported;
+}
+
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
     return ComposerService::getComposerService()->clearAnimationFrameStats();
 }
@@ -763,49 +1494,121 @@
             outCapabilities);
 }
 
+status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+                                                                      ui::PixelFormat* outFormat,
+                                                                      ui::Dataspace* outDataspace,
+                                                                      uint8_t* outComponentMask) {
+    return ComposerService::getComposerService()
+            ->getDisplayedContentSamplingAttributes(display, outFormat, outDataspace,
+                                                    outComponentMask);
+}
+
+status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp<IBinder>& display,
+                                                                 bool enable, uint8_t componentMask,
+                                                                 uint64_t maxFrames) {
+    return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable,
+                                                                                   componentMask,
+                                                                                   maxFrames);
+}
+
+status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display,
+                                                          uint64_t maxFrames, uint64_t timestamp,
+                                                          DisplayedFrameStats* outStats) {
+    return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
+                                                                            timestamp, outStats);
+}
+
+status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
+                                                   bool* outIsWideColorDisplay) {
+    return ComposerService::getComposerService()->isWideColorDisplay(display,
+                                                                     outIsWideColorDisplay);
+}
+
+status_t SurfaceComposerClient::addRegionSamplingListener(
+        const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+        const sp<IRegionSamplingListener>& listener) {
+    return ComposerService::getComposerService()->addRegionSamplingListener(samplingArea,
+                                                                            stopLayerHandle,
+                                                                            listener);
+}
+
+status_t SurfaceComposerClient::removeRegionSamplingListener(
+        const sp<IRegionSamplingListener>& listener) {
+    return ComposerService::getComposerService()->removeRegionSamplingListener(listener);
+}
+
+bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
+    bool support = false;
+    ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
+    return support;
+}
+
+status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
+                                                     float brightness) {
+    return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
+}
+
+status_t SurfaceComposerClient::notifyPowerHint(int32_t hintId) {
+    return ComposerService::getComposerService()->notifyPowerHint(hintId);
+}
+
 // ----------------------------------------------------------------------------
 
-status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
-                                   uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
-                                   bool useIdentityTransform, uint32_t rotation,
-                                   bool captureSecureLayers, sp<GraphicBuffer>* outBuffer,
-                                   bool& outCapturedSecureLayers) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   uint32_t rotation, bool captureSecureLayers,
+                                   sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
-    status_t ret = s->captureScreen(display, outBuffer, outCapturedSecureLayers, sourceCrop,
-                                    reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform,
-                                    static_cast<ISurfaceComposer::Rotation>(rotation),
-                                    captureSecureLayers);
+    if (s == nullptr) return NO_INIT;
+    status_t ret =
+            s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
+                             reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform,
+                             static_cast<ISurfaceComposer::Rotation>(rotation),
+                             captureSecureLayers);
     if (ret != NO_ERROR) {
         return ret;
     }
     return ret;
 }
 
-status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
-                                   uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
-                                   bool useIdentityTransform, uint32_t rotation,
-                                   sp<GraphicBuffer>* outBuffer) {
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
     bool ignored;
-    return capture(display, sourceCrop, reqWidth, reqHeight,
-                   minLayerZ, maxLayerZ, useIdentityTransform, rotation, false, outBuffer, ignored);
+    return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, reqHeight,
+                   useIdentityTransform, rotation, false, outBuffer, ignored);
 }
 
-status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
+status_t ScreenshotClient::capture(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
+                                   sp<GraphicBuffer>* outBuffer) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == nullptr) return NO_INIT;
+    return s->captureScreen(displayOrLayerStack, outDataspace, outBuffer);
+}
+
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
+                                         const ui::Dataspace reqDataSpace,
+                                         const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                          float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
-    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
-                                    false /* childrenOnly */);
+    if (s == nullptr) return NO_INIT;
+    status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat,
+                                    sourceCrop, {}, frameScale, false /* childrenOnly */);
     return ret;
 }
 
-status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
-                                              float frameScale, sp<GraphicBuffer>* outBuffer) {
+status_t ScreenshotClient::captureChildLayers(
+        const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+        const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+        const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles,
+        float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
-    status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
-                                    true /* childrenOnly */);
+    if (s == nullptr) return NO_INIT;
+    status_t ret =
+            s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
+                             excludeHandles, frameScale, true /* childrenOnly */);
     return ret;
 }
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 5eafbb3..55488da 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -54,19 +54,34 @@
 {
 }
 
+SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
+    mClient = other->mClient;
+    mHandle = other->mHandle;
+    mGraphicBufferProducer = other->mGraphicBufferProducer;
+    mOwned = false;
+}
+
 SurfaceControl::~SurfaceControl()
 {
-    destroy();
+    // Avoid reparenting the server-side surface to null if we are not the owner of it,
+    // meaning that we retrieved it from another process.
+    if (mClient != nullptr && mHandle != nullptr && mOwned) {
+        SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
+    }
+    release();
 }
 
 void SurfaceControl::destroy()
 {
-    // Avoid destroying the server-side surface if we are not the owner of it, meaning that we
-    // retrieved it from another process.
-    if (isValid() && mOwned) {
-        mClient->destroySurface(mHandle);
+    if (isValid()) {
+        SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
     }
-    // clear all references and trigger an IPC now, to make sure things
+    release();
+}
+
+void SurfaceControl::release()
+{
+    // Trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
     mClient.clear();
     mHandle.clear();
@@ -74,19 +89,8 @@
     IPCThreadState::self()->flushCommands();
 }
 
-void SurfaceControl::clear()
-{
-    // here, the window manager tells us explicitly that we should destroy
-    // the surface's resource. Soon after this call, it will also release
-    // its last reference (which will call the dtor); however, it is possible
-    // that a client living in the same process still holds references which
-    // would delay the call to the dtor -- that is why we need this explicit
-    // "clear()" call.
-    destroy();
-}
-
 void SurfaceControl::disconnect() {
-    if (mGraphicBufferProducer != NULL) {
+    if (mGraphicBufferProducer != nullptr) {
         mGraphicBufferProducer->disconnect(
                 BufferQueueCore::CURRENTLY_CONNECTED_API);
     }
@@ -95,28 +99,28 @@
 bool SurfaceControl::isSameSurface(
         const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
 {
-    if (lhs == 0 || rhs == 0)
+    if (lhs == nullptr || rhs == nullptr)
         return false;
     return lhs->mHandle == rhs->mHandle;
 }
 
 status_t SurfaceControl::clearLayerFrameStats() const {
     status_t err = validate();
-    if (err < 0) return err;
+    if (err != NO_ERROR) return err;
     const sp<SurfaceComposerClient>& client(mClient);
     return client->clearLayerFrameStats(mHandle);
 }
 
 status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const {
     status_t err = validate();
-    if (err < 0) return err;
+    if (err != NO_ERROR) return err;
     const sp<SurfaceComposerClient>& client(mClient);
     return client->getLayerFrameStats(mHandle, outStats);
 }
 
 status_t SurfaceControl::validate() const
 {
-    if (mHandle==0 || mClient==0) {
+    if (mHandle==nullptr || mClient==nullptr) {
         ALOGE("invalid handle (%p) or client (%p)",
                 mHandle.get(), mClient.get());
         return NO_INIT;
@@ -128,7 +132,7 @@
         const sp<SurfaceControl>& control, Parcel* parcel)
 {
     sp<IGraphicBufferProducer> bp;
-    if (control != NULL) {
+    if (control != nullptr) {
         bp = control->mGraphicBufferProducer;
     }
     return parcel->writeStrongBinder(IInterface::asBinder(bp));
@@ -146,7 +150,7 @@
 sp<Surface> SurfaceControl::getSurface() const
 {
     Mutex::Autolock _l(mLock);
-    if (mSurfaceData == 0) {
+    if (mSurfaceData == nullptr) {
         return generateSurfaceLocked();
     }
     return mSurfaceData;
@@ -164,6 +168,12 @@
     return mHandle;
 }
 
+sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() const
+{
+    Mutex::Autolock _l(mLock);
+    return mGraphicBufferProducer;
+}
+
 sp<SurfaceComposerClient> SurfaceControl::getClient() const
 {
     return mClient;
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index afa15c5..fcae05c 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -41,7 +41,7 @@
     // This can only be called after EGL has been initialized; otherwise the
     // check below will abort.
     const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed");
+    LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed");
     if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
         // This makes GLConsumer use the EGL_ANDROID_native_fence_sync
         // extension to create Android native fences to signal when all
diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp
new file mode 100644
index 0000000..5cb3593
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/Conversion.cpp
@@ -0,0 +1,1542 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/bufferqueue/1.0/Conversion.h>
+
+namespace android {
+namespace conversion {
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+native_handle_t* native_handle_create_from_fd(int fd) {
+    if (fd < 2) {
+        return native_handle_create(0, 0);
+    }
+    native_handle_t* nh = native_handle_create(1, 0);
+    if (nh == nullptr) {
+        return nullptr;
+    }
+    nh->data[0] = fd;
+    return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+int native_handle_read_fd(native_handle_t const* nh, int index) {
+    return ((nh == nullptr) || (nh->numFds == 0) ||
+            (nh->numFds <= index) || (index < 0)) ?
+            -1 : nh->data[index];
+}
+
+/**
+ * Conversion functions
+ * ====================
+ *
+ * There are two main directions of conversion:
+ * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the
+ *   input. The wrapper has type `TargetType`.
+ * - `toTargetType(...)`: Create a standalone object of type `TargetType` that
+ *   corresponds to the input. The lifetime of the output does not depend on the
+ *   lifetime of the input.
+ * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType`
+ *   that cannot be copied and/or moved efficiently, or when there are multiple
+ *   output arguments.
+ * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for
+ *   `TargetType` that cannot be copied and/or moved efficiently, or when there
+ *   are multiple output arguments.
+ *
+ * `wrapIn()` and `convertTo()` functions will take output arguments before
+ * input arguments. Some of these functions might return a value to indicate
+ * success or error.
+ *
+ * In converting or wrapping something as a Treble type that contains a
+ * `hidl_handle`, `native_handle_t*` will need to be created and returned as
+ * an additional output argument, hence only `wrapIn()` or `convertTo()` would
+ * be available. The caller must call `native_handle_delete()` to deallocate the
+ * returned native handle when it is no longer needed.
+ *
+ * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do
+ * not perform duplication of file descriptors, while `toTargetType()` and
+ * `convertTo()` do.
+ */
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+status_t toStatusT(Return<void> const& t) {
+    return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR);
+}
+
+/**
+ * \brief Convert `Return<void>` to `binder::Status`.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `binder::Status`.
+ */
+// convert: Return<void> -> ::android::binder::Status
+::android::binder::Status toBinderStatus(
+        Return<void> const& t) {
+    return ::android::binder::Status::fromExceptionCode(
+            toStatusT(t),
+            t.description().c_str());
+}
+
+/**
+ * \brief Wrap `native_handle_t*` in `hidl_handle`.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \return The `hidl_handle` that points to \p nh.
+ */
+// wrap: native_handle_t* -> hidl_handle
+hidl_handle inHidlHandle(native_handle_t const* nh) {
+    return hidl_handle(nh);
+}
+
+/**
+ * \brief Convert `int32_t` to `Dataspace`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \result The corresponding `Dataspace`.
+ */
+// convert: int32_t -> Dataspace
+Dataspace toHardwareDataspace(int32_t l) {
+    return static_cast<Dataspace>(l);
+}
+
+/**
+ * \brief Convert `Dataspace` to `int32_t`.
+ *
+ * \param[in] t The source `Dataspace`.
+ * \result The corresponding `int32_t`.
+ */
+// convert: Dataspace -> int32_t
+int32_t toRawDataspace(Dataspace const& t) {
+    return static_cast<int32_t>(t);
+}
+
+/**
+ * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that points to the buffer.
+ */
+// wrap: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+    hidl_vec<uint8_t> t;
+    t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+    return t;
+}
+
+/**
+ * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
+ */
+// convert: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
+    hidl_vec<uint8_t> t;
+    t.resize(size);
+    uint8_t const* src = static_cast<uint8_t const*>(l);
+    std::copy(src, src + size, t.data());
+    return t;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+    t->attr.width = l.getWidth();
+    t->attr.height = l.getHeight();
+    t->attr.stride = l.getStride();
+    t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+    t->attr.layerCount = l.getLayerCount();
+    t->attr.usage = static_cast<uint32_t>(l.getUsage());
+    t->attr.id = l.getId();
+    t->attr.generationNumber = l.getGenerationNumber();
+    t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+    native_handle_t* handle = t.nativeHandle == nullptr ?
+            nullptr : native_handle_clone(t.nativeHandle);
+
+    size_t const numInts = 12 + static_cast<size_t>(handle ? handle->numInts : 0);
+    int32_t* ints = new int32_t[numInts];
+
+    size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+    int* fds = new int[numFds];
+
+    ints[0] = 'GBFR';
+    ints[1] = static_cast<int32_t>(t.attr.width);
+    ints[2] = static_cast<int32_t>(t.attr.height);
+    ints[3] = static_cast<int32_t>(t.attr.stride);
+    ints[4] = static_cast<int32_t>(t.attr.format);
+    ints[5] = static_cast<int32_t>(t.attr.layerCount);
+    ints[6] = static_cast<int32_t>(t.attr.usage);
+    ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+    ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+    ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+    ints[10] = 0;
+    ints[11] = 0;
+    if (handle) {
+        ints[10] = static_cast<int32_t>(handle->numFds);
+        ints[11] = static_cast<int32_t>(handle->numInts);
+        int* intsStart = handle->data + handle->numFds;
+        std::copy(handle->data, intsStart, fds);
+        std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+    }
+
+    void const* constBuffer = static_cast<void const*>(ints);
+    size_t size = numInts * sizeof(int32_t);
+    int const* constFds = static_cast<int const*>(fds);
+    status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+    delete [] fds;
+    delete [] ints;
+    native_handle_delete(handle);
+    return status == NO_ERROR;
+}
+
+/**
+ * Conversion functions for types outside media
+ * ============================================
+ *
+ * Some objects in libui and libgui that were made to go through binder calls do
+ * not expose ways to read or write their fields to the public. To pass an
+ * object of this kind through the HIDL boundary, translation functions need to
+ * work around the access restriction by using the publicly available
+ * `flatten()` and `unflatten()` functions.
+ *
+ * All `flatten()` and `unflatten()` overloads follow the same convention as
+ * follows:
+ *
+ *     status_t flatten(ObjectType const& object,
+ *                      [OtherType const& other, ...]
+ *                      void*& buffer, size_t& size,
+ *                      int*& fds, size_t& numFds)
+ *
+ *     status_t unflatten(ObjectType* object,
+ *                        [OtherType* other, ...,]
+ *                        void*& buffer, size_t& size,
+ *                        int*& fds, size_t& numFds)
+ *
+ * The number of `other` parameters varies depending on the `ObjectType`. For
+ * example, in the process of unflattening an object that contains
+ * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will
+ * be created.
+ *
+ * The last four parameters always work the same way in all overloads of
+ * `flatten()` and `unflatten()`:
+ * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled,
+ *   `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`,
+ *   `fds` is the pointer to the fd buffer to be filled, and `numFds` is the
+ *   size (in ints) of the fd buffer pointed to by `fds`.
+ * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read
+ *   from, `size` is the size (in bytes) of the non-fd buffer pointed to by
+ *   `buffer`, `fds` is the pointer to the fd buffer to be read from, and
+ *   `numFds` is the size (in ints) of the fd buffer pointed to by `fds`.
+ * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds`
+ *   will be advanced, while `size` and `numFds` will be decreased to reflect
+ *   how much storage/data of the two buffers (fd and non-fd) have been used.
+ * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and
+ *   `numFds` are invalid.
+ *
+ * The return value of a successful `flatten()` or `unflatten()` call will be
+ * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure.
+ *
+ * For each object type that supports flattening, there will be two accompanying
+ * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will
+ * return the size of the non-fd buffer that the object will need for
+ * flattening. `getFdCount()` will return the size of the fd buffer that the
+ * object will need for flattening.
+ *
+ * The set of these four functions, `getFlattenedSize()`, `getFdCount()`,
+ * `flatten()` and `unflatten()`, are similar to functions of the same name in
+ * the abstract class `Flattenable`. The only difference is that functions in
+ * this file are not member functions of the object type. For example, we write
+ *
+ *     flatten(x, buffer, size, fds, numFds)
+ *
+ * instead of
+ *
+ *     x.flatten(buffer, size, fds, numFds)
+ *
+ * because we cannot modify the type of `x`.
+ *
+ * There is one exception to the naming convention: `hidl_handle` that
+ * represents a fence. The four functions for this "Fence" type have the word
+ * "Fence" attched to their names because the object type, which is
+ * `hidl_handle`, does not carry the special meaning that the object itself can
+ * only contain zero or one file descriptor.
+ */
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
+    return 4;
+};
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+size_t getFenceFdCount(hidl_handle const& fence) {
+    return native_handle_read_fd(fence) == -1 ? 0 : 1;
+}
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+    if (size < 4) {
+        return NO_MEMORY;
+    }
+
+    uint32_t numFdsInHandle;
+    FlattenableUtils::read(buffer, size, numFdsInHandle);
+
+    if (numFdsInHandle > 1) {
+        return BAD_VALUE;
+    }
+
+    if (numFds < numFdsInHandle) {
+        return NO_MEMORY;
+    }
+
+    if (numFdsInHandle) {
+        *nh = native_handle_create_from_fd(*fds);
+        if (*nh == nullptr) {
+            return NO_MEMORY;
+        }
+        *fence = *nh;
+        ++fds;
+        --numFds;
+    } else {
+        *nh = nullptr;
+        *fence = hidl_handle();
+    }
+
+    return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] t The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flattenFence(hidl_handle const& fence,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+    if (size < getFenceFlattenedSize(fence) ||
+            numFds < getFenceFdCount(fence)) {
+        return NO_MEMORY;
+    }
+    // Cast to uint32_t since the size of a size_t can vary between 32- and
+    // 64-bit processes
+    FlattenableUtils::write(buffer, size,
+            static_cast<uint32_t>(getFenceFdCount(fence)));
+    int fd = native_handle_read_fd(fence);
+    if (fd != -1) {
+        *fds = fd;
+        ++fds;
+        --numFds;
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
+    size_t const baseSize = l.getFlattenedSize();
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    size_t const baseNumFds = l.getFdCount();
+    std::unique_ptr<int[]> baseFds(
+            new (std::nothrow) int[baseNumFds]);
+    if (!baseFds) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    int* fds = static_cast<int*>(baseFds.get());
+    size_t numFds = baseNumFds;
+    if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    int const* constFds = static_cast<int const*>(baseFds.get());
+    numFds = baseNumFds;
+    if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
+            != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+bool convertTo(Fence* l, hidl_handle const& t) {
+    int fd = native_handle_read_fd(t);
+    if (fd != -1) {
+        fd = dup(fd);
+        if (fd == -1) {
+            return false;
+        }
+    }
+    native_handle_t* nh = native_handle_create_from_fd(fd);
+    if (nh == nullptr) {
+        if (fd != -1) {
+            close(fd);
+        }
+        return false;
+    }
+
+    size_t const baseSize = getFenceFlattenedSize(t);
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        native_handle_delete(nh);
+        return false;
+    }
+
+    size_t const baseNumFds = getFenceFdCount(t);
+    std::unique_ptr<int[]> baseFds(
+            new (std::nothrow) int[baseNumFds]);
+    if (!baseFds) {
+        native_handle_delete(nh);
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    int* fds = static_cast<int*>(baseFds.get());
+    size_t numFds = baseNumFds;
+    if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
+        native_handle_delete(nh);
+        return false;
+    }
+    native_handle_delete(nh);
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    int const* constFds = static_cast<int const*>(baseFds.get());
+    numFds = baseNumFds;
+    if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+        HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+    constexpr size_t min = sizeof(t.state);
+    switch (t.state) {
+        case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+            return min;
+        case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+            return min + getFenceFlattenedSize(t.fence);
+        case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+            return min + sizeof(
+                    ::android::FenceTime::Snapshot::signalTime);
+    }
+    return 0;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+size_t getFdCount(
+        HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+    return t.state ==
+            HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
+            getFenceFdCount(t.fence) : 0;
+}
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`.
+ */
+status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+    if (size < getFlattenedSize(t)) {
+        return NO_MEMORY;
+    }
+
+    switch (t.state) {
+        case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+            FlattenableUtils::write(buffer, size,
+                    ::android::FenceTime::Snapshot::State::EMPTY);
+            return NO_ERROR;
+        case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+            FlattenableUtils::write(buffer, size,
+                    ::android::FenceTime::Snapshot::State::FENCE);
+            return flattenFence(t.fence, buffer, size, fds, numFds);
+        case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+            FlattenableUtils::write(buffer, size,
+                    ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
+            FlattenableUtils::write(buffer, size, t.signalTimeNs);
+            return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `FenceTimeSnapshot`.
+ *
+ * \param[out] t The destination `FenceTimeSnapshot`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and the constructed snapshot contains a
+ * file descriptor, \p nh will be created to hold that file descriptor. In this
+ * case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
+ */
+status_t unflatten(
+        HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+    if (size < sizeof(t->state)) {
+        return NO_MEMORY;
+    }
+
+    *nh = nullptr;
+    ::android::FenceTime::Snapshot::State state;
+    FlattenableUtils::read(buffer, size, state);
+    switch (state) {
+        case ::android::FenceTime::Snapshot::State::EMPTY:
+            t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
+            return NO_ERROR;
+        case ::android::FenceTime::Snapshot::State::FENCE:
+            t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
+            return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
+        case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
+            t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
+            if (size < sizeof(t->signalTimeNs)) {
+                return NO_MEMORY;
+            }
+            FlattenableUtils::read(buffer, size, t->signalTimeNs);
+            return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return a lower bound on the size of the non-fd buffer required to
+ * flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+        HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
+    return sizeof(uint64_t) + // mFrameNumber
+            sizeof(uint8_t) + // mIndex
+            sizeof(uint8_t) + // mAddPostCompositeCalled
+            sizeof(uint8_t) + // mAddRetireCalled
+            sizeof(uint8_t) + // mAddReleaseCalled
+            sizeof(nsecs_t) + // mPostedTime
+            sizeof(nsecs_t) + // mRequestedPresentTime
+            sizeof(nsecs_t) + // mLatchTime
+            sizeof(nsecs_t) + // mFirstRefreshStartTime
+            sizeof(nsecs_t); // mLastRefreshStartTime
+}
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+        HGraphicBufferProducer::FrameEventsDelta const& t) {
+    return minFlattenedSize(t) +
+            getFlattenedSize(t.gpuCompositionDoneFence) +
+            getFlattenedSize(t.displayPresentFence) +
+            getFlattenedSize(t.displayRetireFence) +
+            getFlattenedSize(t.releaseFence);
+};
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+        HGraphicBufferProducer::FrameEventsDelta const& t) {
+    return getFdCount(t.gpuCompositionDoneFence) +
+            getFdCount(t.displayPresentFence) +
+            getFdCount(t.displayRetireFence) +
+            getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Unflatten `FrameEventsDelta`.
+ *
+ * \param[out] t The destination `FrameEventsDelta`.
+ * \param[out] nh The underlying array of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be
+ * populated with `nullptr` or newly created handles. Each non-null slot in \p
+ * nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+        std::vector<native_handle_t*>* nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+    if (size < minFlattenedSize(*t)) {
+        return NO_MEMORY;
+    }
+    FlattenableUtils::read(buffer, size, t->frameNumber);
+
+    // These were written as uint8_t for alignment.
+    uint8_t temp = 0;
+    FlattenableUtils::read(buffer, size, temp);
+    size_t index = static_cast<size_t>(temp);
+    if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    t->index = static_cast<uint32_t>(index);
+
+    FlattenableUtils::read(buffer, size, temp);
+    t->addPostCompositeCalled = static_cast<bool>(temp);
+    FlattenableUtils::read(buffer, size, temp);
+    t->addRetireCalled = static_cast<bool>(temp);
+    FlattenableUtils::read(buffer, size, temp);
+    t->addReleaseCalled = static_cast<bool>(temp);
+
+    FlattenableUtils::read(buffer, size, t->postedTimeNs);
+    FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
+    FlattenableUtils::read(buffer, size, t->latchTimeNs);
+    FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
+    FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
+    FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
+
+    // Fences
+    HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
+    tSnapshot[0] = &t->gpuCompositionDoneFence;
+    tSnapshot[1] = &t->displayPresentFence;
+    tSnapshot[2] = &t->displayRetireFence;
+    tSnapshot[3] = &t->releaseFence;
+    nh->resize(4);
+    for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+        status_t status = unflatten(
+                tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
+                buffer, size, fds, numFds);
+        if (status != NO_ERROR) {
+            while (snapshotIndex > 0) {
+                --snapshotIndex;
+                if ((*nh)[snapshotIndex] != nullptr) {
+                    native_handle_delete((*nh)[snapshotIndex]);
+                }
+            }
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+//      FrameEventsDelta::flatten
+status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+        void*& buffer, size_t& size, int*& fds, size_t numFds) {
+    // Check that t.index is within a valid range.
+    if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
+            || t.index > std::numeric_limits<uint8_t>::max()) {
+        return BAD_VALUE;
+    }
+
+    FlattenableUtils::write(buffer, size, t.frameNumber);
+
+    // These are static_cast to uint8_t for alignment.
+    FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(t.addRetireCalled));
+    FlattenableUtils::write(
+            buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
+
+    FlattenableUtils::write(buffer, size, t.postedTimeNs);
+    FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
+    FlattenableUtils::write(buffer, size, t.latchTimeNs);
+    FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
+    FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
+    FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
+
+    // Fences
+    HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
+    tSnapshot[0] = &t.gpuCompositionDoneFence;
+    tSnapshot[1] = &t.displayPresentFence;
+    tSnapshot[2] = &t.displayRetireFence;
+    tSnapshot[3] = &t.releaseFence;
+    for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+        status_t status = flatten(
+                *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+    size_t size = 4 + // mDeltas.size()
+            sizeof(t.compositorTiming);
+    for (size_t i = 0; i < t.deltas.size(); ++i) {
+        size += getFlattenedSize(t.deltas[i]);
+    }
+    return size;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+    size_t numFds = 0;
+    for (size_t i = 0; i < t.deltas.size(); ++i) {
+        numFds += getFdCount(t.deltas[i]);
+    }
+    return numFds;
+}
+
+/**
+ * \brief Unflatten `FrameEventHistoryDelta`.
+ *
+ * \param[out] t The destination `FrameEventHistoryDelta`.
+ * \param[out] nh The underlying array of arrays of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or
+ * newly created handles. The second dimension of \p nh will be 4. Each non-null
+ * slot in \p nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(
+        HGraphicBufferProducer::FrameEventHistoryDelta* t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+    if (size < 4) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, t->compositorTiming);
+
+    uint32_t deltaCount = 0;
+    FlattenableUtils::read(buffer, size, deltaCount);
+    if (static_cast<size_t>(deltaCount) >
+            ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    t->deltas.resize(deltaCount);
+    nh->resize(deltaCount);
+    for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
+        status_t status = unflatten(
+                &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
+                buffer, size, fds, numFds);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+status_t flatten(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+    if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+        return BAD_VALUE;
+    }
+    if (size < getFlattenedSize(t)) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+    FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+    for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+        status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `::android::FrameEventHistoryData` in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `::android::FrameEventHistoryDelta`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        ::android::FrameEventHistoryDelta const& l) {
+
+    size_t const baseSize = l.getFlattenedSize();
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    size_t const baseNumFds = l.getFdCount();
+    std::unique_ptr<int[]> baseFds(
+            new (std::nothrow) int[baseNumFds]);
+    if (!baseFds) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    int* fds = baseFds.get();
+    size_t numFds = baseNumFds;
+    if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    int const* constFds = static_cast<int const*>(baseFds.get());
+    numFds = baseNumFds;
+    if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+bool convertTo(
+        ::android::FrameEventHistoryDelta* l,
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+
+    size_t const baseSize = getFlattenedSize(t);
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    size_t const baseNumFds = getFdCount(t);
+    std::unique_ptr<int[]> baseFds(
+            new (std::nothrow) int[baseNumFds]);
+    if (!baseFds) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    int* fds = static_cast<int*>(baseFds.get());
+    size_t numFds = baseNumFds;
+    if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    int const* constFds = static_cast<int const*>(baseFds.get());
+    numFds = baseNumFds;
+    if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Return the size of the buffer required to flatten `Region`.
+ *
+ * \param[in] t The input `Region`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(Region const& t) {
+    return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
+}
+
+/**
+ * \brief Unflatten `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t unflatten(Region* t, void const*& buffer, size_t& size) {
+    if (size < sizeof(uint32_t)) {
+        return NO_MEMORY;
+    }
+
+    uint32_t numRects = 0;
+    FlattenableUtils::read(buffer, size, numRects);
+    if (size < numRects * sizeof(Rect)) {
+        return NO_MEMORY;
+    }
+    if (numRects > (UINT32_MAX / sizeof(Rect))) {
+        return NO_MEMORY;
+    }
+
+    t->resize(numRects);
+    for (size_t r = 0; r < numRects; ++r) {
+        ::android::Rect rect(::android::Rect::EMPTY_RECT);
+        status_t status = rect.unflatten(buffer, size);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        FlattenableUtils::advance(buffer, size, sizeof(rect));
+        (*t)[r] = Rect{
+                static_cast<int32_t>(rect.left),
+                static_cast<int32_t>(rect.top),
+                static_cast<int32_t>(rect.right),
+                static_cast<int32_t>(rect.bottom)};
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `Region`.
+ *
+ * \param[in] t The source `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flatten(Region const& t, void*& buffer, size_t& size) {
+    if (size < getFlattenedSize(t)) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
+    for (size_t r = 0; r < t.size(); ++r) {
+        ::android::Rect rect(
+                static_cast<int32_t>(t[r].left),
+                static_cast<int32_t>(t[r].top),
+                static_cast<int32_t>(t[r].right),
+                static_cast<int32_t>(t[r].bottom));
+        status_t status = rect.flatten(buffer, size);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        FlattenableUtils::advance(buffer, size, sizeof(rect));
+    }
+    return NO_ERROR;
+}
+
+/**
+ * \brief Convert `::android::Region` to `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in] l The source `::android::Region`.
+ */
+// convert: ::android::Region -> Region
+bool convertTo(Region* t, ::android::Region const& l) {
+    size_t const baseSize = l.getFlattenedSize();
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    if (l.flatten(buffer, size) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    if (unflatten(t, constBuffer, size) != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * \brief Convert `Region` to `::android::Region`.
+ *
+ * \param[out] l The destination `::android::Region`.
+ * \param[in] t The source `Region`.
+ */
+// convert: Region -> ::android::Region
+bool convertTo(::android::Region* l, Region const& t) {
+    size_t const baseSize = getFlattenedSize(t);
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    if (flatten(t, buffer, size) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    if (l->unflatten(constBuffer, size) != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+//      BGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return a lower bound on the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+        HGraphicBufferProducer::QueueBufferInput const& /* t */) {
+    return sizeof(int64_t) + // timestamp
+            sizeof(int) + // isAutoTimestamp
+            sizeof(android_dataspace) + // dataSpace
+            sizeof(::android::Rect) + // crop
+            sizeof(int) + // scalingMode
+            sizeof(uint32_t) + // transform
+            sizeof(uint32_t) + // stickyTransform
+            sizeof(bool); // getFrameTimestamps
+}
+
+/**
+ * \brief Return the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
+    return minFlattenedSize(t) +
+            getFenceFlattenedSize(t.fence) +
+            getFlattenedSize(t.surfaceDamage) +
+            sizeof(HdrMetadata::validTypes);
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+        HGraphicBufferProducer::QueueBufferInput const& t) {
+    return getFenceFdCount(t.fence);
+}
+
+/**
+ * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence`. */
+status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+        native_handle_t** nh,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+    if (size < getFlattenedSize(t)) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::write(buffer, size, t.timestamp);
+    FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
+    FlattenableUtils::write(buffer, size,
+            static_cast<android_dataspace_t>(t.dataSpace));
+    FlattenableUtils::write(buffer, size, ::android::Rect(
+            static_cast<int32_t>(t.crop.left),
+            static_cast<int32_t>(t.crop.top),
+            static_cast<int32_t>(t.crop.right),
+            static_cast<int32_t>(t.crop.bottom)));
+    FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
+    FlattenableUtils::write(buffer, size, t.transform);
+    FlattenableUtils::write(buffer, size, t.stickyTransform);
+    FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
+
+    *nh = t.fence.getNativeHandle() == nullptr ?
+            nullptr : native_handle_clone(t.fence);
+    status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    status = flatten(t.surfaceDamage, buffer, size);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
+    return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflatten(
+        HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+    if (size < minFlattenedSize(*t)) {
+        return NO_MEMORY;
+    }
+
+    FlattenableUtils::read(buffer, size, t->timestamp);
+    int lIsAutoTimestamp;
+    FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
+    t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
+    android_dataspace_t lDataSpace;
+    FlattenableUtils::read(buffer, size, lDataSpace);
+    t->dataSpace = static_cast<Dataspace>(lDataSpace);
+    Rect lCrop;
+    FlattenableUtils::read(buffer, size, lCrop);
+    t->crop = Rect{
+            static_cast<int32_t>(lCrop.left),
+            static_cast<int32_t>(lCrop.top),
+            static_cast<int32_t>(lCrop.right),
+            static_cast<int32_t>(lCrop.bottom)};
+    int lScalingMode;
+    FlattenableUtils::read(buffer, size, lScalingMode);
+    t->scalingMode = static_cast<int32_t>(lScalingMode);
+    FlattenableUtils::read(buffer, size, t->transform);
+    FlattenableUtils::read(buffer, size, t->stickyTransform);
+    FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
+
+    status_t status = unflattenFence(&(t->fence), nh,
+            buffer, size, fds, numFds);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    // HdrMetadata ignored
+    return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+bool wrapAs(
+        HGraphicBufferProducer::QueueBufferInput* t,
+        native_handle_t** nh,
+        BGraphicBufferProducer::QueueBufferInput const& l) {
+
+    size_t const baseSize = l.getFlattenedSize();
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    size_t const baseNumFds = l.getFdCount();
+    std::unique_ptr<int[]> baseFds(
+            new (std::nothrow) int[baseNumFds]);
+    if (!baseFds) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    int* fds = baseFds.get();
+    size_t numFds = baseNumFds;
+    if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    int const* constFds = static_cast<int const*>(baseFds.get());
+    numFds = baseNumFds;
+    if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
+ * `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If `t.fence` has a valid file descriptor, it will be duplicated.
+ */
+bool convertTo(
+        BGraphicBufferProducer::QueueBufferInput* l,
+        HGraphicBufferProducer::QueueBufferInput const& t) {
+
+    size_t const baseSize = getFlattenedSize(t);
+    std::unique_ptr<uint8_t[]> baseBuffer(
+            new (std::nothrow) uint8_t[baseSize]);
+    if (!baseBuffer) {
+        return false;
+    }
+
+    size_t const baseNumFds = getFdCount(t);
+    std::unique_ptr<int[]> baseFds(
+            new (std::nothrow) int[baseNumFds]);
+    if (!baseFds) {
+        return false;
+    }
+
+    void* buffer = static_cast<void*>(baseBuffer.get());
+    size_t size = baseSize;
+    int* fds = baseFds.get();
+    size_t numFds = baseNumFds;
+    native_handle_t* nh;
+    if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
+        return false;
+    }
+
+    void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+    size = baseSize;
+    int const* constFds = static_cast<int const*>(baseFds.get());
+    numFds = baseNumFds;
+    if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+        if (nh != nullptr) {
+            native_handle_close(nh);
+            native_handle_delete(nh);
+        }
+        return false;
+    }
+
+    native_handle_delete(nh);
+    return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+//      BGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+// wrap: BGraphicBufferProducer::QueueBufferOutput ->
+// HGraphicBufferProducer::QueueBufferOutput
+bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        BGraphicBufferProducer::QueueBufferOutput const& l) {
+    if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
+        return false;
+    }
+    t->width = l.width;
+    t->height = l.height;
+    t->transformHint = l.transformHint;
+    t->numPendingBuffers = l.numPendingBuffers;
+    t->nextFrameNumber = l.nextFrameNumber;
+    t->bufferReplaced = l.bufferReplaced;
+    return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// BGraphicBufferProducer::QueueBufferOutput
+bool convertTo(
+        BGraphicBufferProducer::QueueBufferOutput* l,
+        HGraphicBufferProducer::QueueBufferOutput const& t) {
+    if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
+        return false;
+    }
+    l->width = t.width;
+    l->height = t.height;
+    l->transformHint = t.transformHint;
+    l->numPendingBuffers = t.numPendingBuffers;
+    l->nextFrameNumber = t.nextFrameNumber;
+    l->bufferReplaced = t.bufferReplaced;
+    return true;
+}
+
+/**
+ * \brief Convert `BGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+        BGraphicBufferProducer::DisconnectMode l) {
+    switch (l) {
+        case BGraphicBufferProducer::DisconnectMode::Api:
+            return HGraphicBufferProducer::DisconnectMode::API;
+        case BGraphicBufferProducer::DisconnectMode::AllLocal:
+            return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
+    }
+    return HGraphicBufferProducer::DisconnectMode::API;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::DisconnectMode` to
+ * `BGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
+ */
+BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+        HGraphicBufferProducer::DisconnectMode t) {
+    switch (t) {
+        case HGraphicBufferProducer::DisconnectMode::API:
+            return BGraphicBufferProducer::DisconnectMode::Api;
+        case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
+            return BGraphicBufferProducer::DisconnectMode::AllLocal;
+    }
+    return BGraphicBufferProducer::DisconnectMode::Api;
+}
+
+}  // namespace conversion
+}  // namespace android
+
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index fe99620..cee1b81 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -100,7 +100,12 @@
  */
 // convert: Return<Status> -> status_t
 inline status_t toStatusT(Return<Status> const& t) {
-    return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) : UNKNOWN_ERROR;
+    if (t.isOk()) {
+        return static_cast<status_t>(static_cast<Status>(t));
+    } else if (t.isDeadObject()) {
+        return DEAD_OBJECT;
+    }
+    return UNKNOWN_ERROR;
 }
 
 /**
@@ -111,7 +116,7 @@
  */
 // convert: Return<void> -> status_t
 inline status_t toStatusT(Return<void> const& t) {
-    return t.isOk() ? OK : UNKNOWN_ERROR;
+    return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR);
 }
 
 /**
@@ -896,7 +901,7 @@
     int const* constFds = static_cast<int const*>(baseFds.get());
     numFds = baseNumFds;
     if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
-        for (auto nhA : nhAA) {
+        for (const auto& nhA : nhAA) {
             for (auto nh : nhA) {
                 if (nh != nullptr) {
                     native_handle_close(nh);
@@ -907,8 +912,8 @@
         return false;
     }
 
-    for (auto nhA : nhAA) {
-        for (auto nh : nhA) {
+    for (const auto& nhA : nhAA) {
+        for (const auto& nh : nhA) {
             if (nh != nullptr) {
                 native_handle_delete(nh);
             }
diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
new file mode 100644
index 0000000..2712f42
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BProducerListener@1.0"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/1.0/H2BProducerListener.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+      : CBase{base} {
+}
+
+void H2BProducerListener::onBufferReleased() {
+    if (!mBase->onBufferReleased().isOk()) {
+        LOG(ERROR) << "onBufferReleased: transaction failed.";
+    }
+}
+
+bool H2BProducerListener::needsReleaseNotify() {
+    Return<bool> transResult = mBase->needsReleaseNotify();
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "needsReleaseNotify: transaction failed.";
+        return false;
+    }
+    return static_cast<bool>(transResult);
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
diff --git a/libs/gui/bufferqueue/1.0/WProducerListener.cpp b/libs/gui/bufferqueue/1.0/WProducerListener.cpp
new file mode 100644
index 0000000..78dc4e8
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/WProducerListener.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/bufferqueue/1.0/WProducerListener.h>
+
+namespace android {
+
+// TWProducerListener
+TWProducerListener::TWProducerListener(
+        sp<BProducerListener> const& base):
+    mBase(base) {
+}
+
+Return<void> TWProducerListener::onBufferReleased() {
+    mBase->onBufferReleased();
+    return Void();
+}
+
+Return<bool> TWProducerListener::needsReleaseNotify() {
+    return mBase->needsReleaseNotify();
+}
+
+// LWProducerListener
+LWProducerListener::LWProducerListener(
+        sp<HProducerListener> const& base):
+    mBase(base) {
+}
+
+void LWProducerListener::onBufferReleased() {
+    mBase->onBufferReleased();
+}
+
+bool LWProducerListener::needsReleaseNotify() {
+    return static_cast<bool>(mBase->needsReleaseNotify());
+}
+
+}  // namespace android
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
new file mode 100644
index 0000000..e891ec5
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "B2HGraphicBufferProducer@2.0"
+
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+namespace /* unnamed */ {
+
+using BQueueBufferInput = ::android::
+        IGraphicBufferProducer::QueueBufferInput;
+using HQueueBufferInput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferInput;
+using BQueueBufferOutput = ::android::
+        IGraphicBufferProducer::QueueBufferOutput;
+using HQueueBufferOutput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferOutput;
+
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
+
+bool b2h(BQueueBufferOutput const& from, HQueueBufferOutput* to) {
+    to->width = from.width;
+    to->height = from.height;
+    to->transformHint = static_cast<int32_t>(from.transformHint);
+    to->numPendingBuffers = from.numPendingBuffers;
+    to->nextFrameNumber = from.nextFrameNumber;
+    to->bufferReplaced = from.bufferReplaced;
+    return true;
+}
+
+} // unnamed namespace
+
+// B2HGraphicBufferProducer
+// ========================
+
+B2HGraphicBufferProducer::B2HGraphicBufferProducer(
+        sp<BGraphicBufferProducer> const& base)
+      : mBase{base} {
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setMaxDequeuedBufferCount(
+        int32_t maxDequeuedBuffers) {
+    HStatus hStatus{};
+    bool converted = b2h(
+            mBase->setMaxDequeuedBufferCount(
+                static_cast<int>(maxDequeuedBuffers)),
+            &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::requestBuffer(
+        int32_t slot,
+        requestBuffer_cb _hidl_cb) {
+    sp<GraphicBuffer> bBuffer;
+    HStatus hStatus{};
+    HardwareBuffer hBuffer{};
+    uint32_t hGenerationNumber{};
+    bool converted =
+            b2h(mBase->requestBuffer(
+                    static_cast<int>(slot), &bBuffer),
+                &hStatus) &&
+            b2h(bBuffer, &hBuffer, &hGenerationNumber);
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+             hBuffer, hGenerationNumber);
+    return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setAsyncMode(bool async) {
+    HStatus hStatus{};
+    bool converted = b2h(mBase->setAsyncMode(async), &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::dequeueBuffer(
+        DequeueBufferInput const& input,
+        dequeueBuffer_cb _hidl_cb) {
+    int bSlot{};
+    sp<BFence> bFence;
+    HStatus hStatus{};
+    DequeueBufferOutput hOutput{};
+    HFenceWrapper hFenceWrapper;
+    bool converted =
+            b2h(mBase->dequeueBuffer(
+                    &bSlot,
+                    &bFence,
+                    input.width,
+                    input.height,
+                    static_cast<PixelFormat>(input.format),
+                    input.usage,
+                    &hOutput.bufferAge,
+                    nullptr /* outTimestamps */),
+                &hStatus,
+                &hOutput.bufferNeedsReallocation,
+                &hOutput.releaseAllBuffers) &&
+            b2h(bFence, &hFenceWrapper);
+    hOutput.fence = hFenceWrapper.getHandle();
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+             static_cast<int32_t>(bSlot),
+             hOutput);
+    return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::detachBuffer(int32_t slot) {
+    HStatus hStatus{};
+    bool converted = b2h(
+            mBase->detachBuffer(static_cast<int>(slot)), &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::detachNextBuffer(
+        detachNextBuffer_cb _hidl_cb) {
+    sp<GraphicBuffer> bBuffer;
+    sp<BFence> bFence;
+    HStatus hStatus{};
+    HardwareBuffer hBuffer{};
+    HFenceWrapper hFenceWrapper;
+    bool converted =
+            b2h(mBase->detachNextBuffer(&bBuffer, &bFence), &hStatus) &&
+            b2h(bBuffer, &hBuffer) &&
+            b2h(bFence, &hFenceWrapper);
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+             hBuffer,
+             hFenceWrapper.getHandle());
+    return {};
+}
+
+Return<void> B2HGraphicBufferProducer::attachBuffer(
+        HardwareBuffer const& hBuffer,
+        uint32_t generationNumber,
+        attachBuffer_cb _hidl_cb) {
+    sp<GraphicBuffer> bBuffer;
+    if (!h2b(hBuffer, &bBuffer) || !bBuffer) {
+        _hidl_cb(HStatus::UNKNOWN_ERROR,
+                 static_cast<int32_t>(SlotIndex::INVALID),
+                 false);
+        return {};
+    }
+    bBuffer->setGenerationNumber(generationNumber);
+
+    int bSlot{};
+    HStatus hStatus{};
+    bool releaseAllBuffers{};
+    bool converted = b2h(
+            mBase->attachBuffer(&bSlot, bBuffer), &hStatus,
+            nullptr /* bufferNeedsReallocation */,
+            &releaseAllBuffers);
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+             static_cast<int32_t>(bSlot),
+             releaseAllBuffers);
+    return {};
+}
+
+Return<void> B2HGraphicBufferProducer::queueBuffer(
+        int32_t slot,
+        QueueBufferInput const& hInput,
+        queueBuffer_cb _hidl_cb) {
+    BQueueBufferInput bInput{
+            hInput.timestamp,
+            hInput.isAutoTimestamp,
+            static_cast<android_dataspace>(hInput.dataSpace),
+            {}, /* crop */
+            0 /* scalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE */,
+            static_cast<uint32_t>(hInput.transform),
+            {}, /* fence */
+            static_cast<uint32_t>(hInput.stickyTransform),
+            false /* getFrameTimestamps */};
+
+    // Convert crop.
+    if (!h2b(hInput.crop, &bInput.crop)) {
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
+        return {};
+    }
+
+    // Convert surfaceDamage.
+    if (!h2b(hInput.surfaceDamage, &bInput.surfaceDamage)) {
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
+        return {};
+    }
+
+    // Convert fence.
+    if (!h2b(hInput.fence, &bInput.fence)) {
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
+        return {};
+    }
+
+    BQueueBufferOutput bOutput{};
+    HStatus hStatus{};
+    QueueBufferOutput hOutput{};
+    bool converted =
+            b2h(
+                mBase->queueBuffer(static_cast<int>(slot), bInput, &bOutput),
+                &hStatus) &&
+            b2h(bOutput, &hOutput);
+
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput);
+    return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::cancelBuffer(
+        int32_t slot,
+        hidl_handle const& fence) {
+    sp<BFence> bFence;
+    if (!h2b(fence.getNativeHandle(), &bFence)) {
+        return {HStatus::UNKNOWN_ERROR};
+    }
+    HStatus hStatus{};
+    bool converted = b2h(
+            mBase->cancelBuffer(static_cast<int>(slot), bFence),
+            &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) {
+    int value{};
+    int result = mBase->query(static_cast<int>(what), &value);
+    _hidl_cb(static_cast<int32_t>(result), static_cast<int32_t>(value));
+    return {};
+}
+
+Return<void> B2HGraphicBufferProducer::connect(
+        sp<HProducerListener> const& hListener,
+        HConnectionType hConnectionType,
+        bool producerControlledByApp,
+        connect_cb _hidl_cb) {
+    sp<BProducerListener> bListener = new H2BProducerListener(hListener);
+    int bConnectionType{};
+    if (!bListener || !h2b(hConnectionType, &bConnectionType)) {
+        _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
+        return {};
+    }
+    BQueueBufferOutput bOutput{};
+    HStatus hStatus{};
+    QueueBufferOutput hOutput{};
+    bool converted =
+            b2h(mBase->connect(bListener,
+                               bConnectionType,
+                               producerControlledByApp,
+                               &bOutput),
+                &hStatus) &&
+            b2h(bOutput, &hOutput);
+    _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput);
+    return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::disconnect(
+        HConnectionType hConnectionType) {
+    int bConnectionType;
+    if (!h2b(hConnectionType, &bConnectionType)) {
+        return {HStatus::UNKNOWN_ERROR};
+    }
+    HStatus hStatus{};
+    bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::allocateBuffers(
+        uint32_t width, uint32_t height,
+        uint32_t format, uint64_t usage) {
+    mBase->allocateBuffers(
+            width, height, static_cast<PixelFormat>(format), usage);
+    return {HStatus::OK};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::allowAllocation(bool allow) {
+    HStatus hStatus{};
+    bool converted = b2h(mBase->allowAllocation(allow), &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setGenerationNumber(
+        uint32_t generationNumber) {
+    HStatus hStatus{};
+    bool converted = b2h(
+            mBase->setGenerationNumber(generationNumber),
+            &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setDequeueTimeout(
+        int64_t timeoutNs) {
+    HStatus hStatus{};
+    bool converted = b2h(
+            mBase->setDequeueTimeout(static_cast<nsecs_t>(timeoutNs)),
+            &hStatus);
+    return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<uint64_t> B2HGraphicBufferProducer::getUniqueId() {
+    uint64_t outId{};
+    HStatus hStatus{};
+    bool converted = b2h(mBase->getUniqueId(&outId), &hStatus);
+    return {converted ? outId : 0};
+}
+
+Return<void> B2HGraphicBufferProducer::getConsumerName(
+        getConsumerName_cb _hidl_cb) {
+    _hidl_cb(hidl_string{mBase->getConsumerName().c_str()});
+    return {};
+}
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp
new file mode 100644
index 0000000..c4c96eb
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/bufferqueue/2.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// B2HProducerListener
+B2HProducerListener::B2HProducerListener(sp<BProducerListener> const& base)
+      : mBase{base},
+        mNeedsReleaseNotify{base ? base->needsReleaseNotify() : false} {
+}
+
+Return<void> B2HProducerListener::onBuffersReleased(uint32_t count) {
+    if (mNeedsReleaseNotify) {
+        for (; count > 0; --count) {
+            mBase->onBufferReleased();
+        }
+    }
+    return {};
+}
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
new file mode 100644
index 0000000..2f5b73c
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
@@ -0,0 +1,506 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BGraphicBufferProducer@2.0"
+
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/bufferqueue/2.0/B2HProducerListener.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+namespace /* unnamed */ {
+
+using BQueueBufferInput = ::android::
+        IGraphicBufferProducer::QueueBufferInput;
+using HQueueBufferInput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferInput;
+using BQueueBufferOutput = ::android::
+        IGraphicBufferProducer::QueueBufferOutput;
+using HQueueBufferOutput = ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer::QueueBufferOutput;
+
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
+using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
+
+bool b2h(BQueueBufferInput const& from, HQueueBufferInput* to,
+         HFenceWrapper* hFenceWrapper) {
+    to->timestamp = from.timestamp;
+    to->isAutoTimestamp = static_cast<bool>(from.isAutoTimestamp);
+    to->dataSpace = static_cast<int32_t>(from.dataSpace);
+    to->transform = static_cast<int32_t>(from.transform);
+    to->stickyTransform = static_cast<int32_t>(from.stickyTransform);
+    if (!b2h(from.crop, &to->crop) ||
+            !b2h(from.surfaceDamage, &to->surfaceDamage) ||
+            !b2h(from.fence, hFenceWrapper)) {
+        return false;
+    }
+    to->fence = hFenceWrapper->getHandle();
+    return true;
+}
+
+bool h2b(HQueueBufferOutput const& from, BQueueBufferOutput* to) {
+    to->width = from.width;
+    to->height = from.height;
+    to->transformHint = static_cast<uint32_t>(from.transformHint);
+    to->numPendingBuffers = from.numPendingBuffers;
+    to->nextFrameNumber = from.nextFrameNumber;
+    to->bufferReplaced = from.bufferReplaced;
+    return true;
+}
+
+} // unnamed namespace
+
+// H2BGraphicBufferProducer
+// ========================
+
+status_t H2BGraphicBufferProducer::requestBuffer(int slot,
+                                                 sp<GraphicBuffer>* bBuffer) {
+    bool converted{};
+    status_t bStatus{};
+    Return<void> transResult = mBase->requestBuffer(slot,
+            [&converted, &bStatus, bBuffer](
+                    HStatus hStatus,
+                    HardwareBuffer const& hBuffer,
+                    uint32_t generationNumber) {
+                converted =
+                        h2b(hStatus, &bStatus) &&
+                        h2b(hBuffer, bBuffer);
+                if (*bBuffer) {
+                    (*bBuffer)->setGenerationNumber(generationNumber);
+                }
+            });
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "requestBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!converted) {
+        LOG(ERROR) << "requestBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->setMaxDequeuedBufferCount(
+            static_cast<int32_t>(maxDequeuedBuffers));
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "setMaxDequeuedBufferCount: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "setMaxDequeuedBufferCount: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setAsyncMode(bool async) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->setAsyncMode(async);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "setAsyncMode: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "setAsyncMode: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::dequeueBuffer(
+        int* slot, sp<BFence>* fence,
+        uint32_t w, uint32_t h,
+        PixelFormat format, uint64_t usage,
+        uint64_t* outBufferAge, FrameEventHistoryDelta* /* outTimestamps */) {
+
+    using HInput = HGraphicBufferProducer::DequeueBufferInput;
+    HInput input{w, h, static_cast<uint32_t>(format), usage};
+
+    using HOutput = HGraphicBufferProducer::DequeueBufferOutput;
+    bool converted{};
+    status_t bStatus{};
+    Return<void> transResult = mBase->dequeueBuffer(input,
+            [&converted, &bStatus, slot, fence, outBufferAge] (
+                    HStatus hStatus, int32_t hSlot, HOutput const& hOutput) {
+                converted = h2b(hStatus, &bStatus);
+                if (!converted || bStatus != OK) {
+                    return;
+                }
+                *slot = hSlot;
+                *outBufferAge = hOutput.bufferAge;
+                bStatus =
+                        (hOutput.bufferNeedsReallocation ?
+                        BUFFER_NEEDS_REALLOCATION : 0) |
+                        (hOutput.releaseAllBuffers ?
+                        RELEASE_ALL_BUFFERS : 0);
+                converted = h2b(hOutput.fence, fence);
+            });
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "dequeueBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!converted) {
+        LOG(ERROR) << "dequeueBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachBuffer(int slot) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->detachBuffer(
+            static_cast<int32_t>(slot));
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "detachBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "detachBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachNextBuffer(
+        sp<GraphicBuffer>* outBuffer, sp<BFence>* outFence) {
+    bool converted{};
+    status_t bStatus{};
+    Return<void> transResult = mBase->detachNextBuffer(
+            [&converted, &bStatus, outBuffer, outFence] (
+                    HStatus hStatus,
+                    HardwareBuffer const& hBuffer,
+                    hidl_handle const& hFence) {
+                converted = h2b(hStatus, &bStatus) &&
+                    h2b(hBuffer, outBuffer) &&
+                    h2b(hFence, outFence);
+            });
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "detachNextBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!converted) {
+        LOG(ERROR) << "detachNextBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::attachBuffer(
+        int* outSlot, sp<GraphicBuffer> const& buffer) {
+    HardwareBuffer hBuffer{};
+    uint32_t hGenerationNumber{};
+    if (!b2h(buffer, &hBuffer, &hGenerationNumber)) {
+        LOG(ERROR) << "attachBuffer: invalid input buffer.";
+        return BAD_VALUE;
+    }
+
+    bool converted{};
+    status_t bStatus{};
+    Return<void> transResult = mBase->attachBuffer(hBuffer, hGenerationNumber,
+            [&converted, &bStatus, outSlot](
+                    HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) {
+                converted = h2b(hStatus, &bStatus);
+                *outSlot = static_cast<int>(hSlot);
+                if (converted && releaseAllBuffers && bStatus == OK) {
+                    bStatus = IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
+                }
+            });
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "attachBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!converted) {
+        LOG(ERROR) << "attachBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::queueBuffer(
+        int slot,
+        QueueBufferInput const& input,
+        QueueBufferOutput* output) {
+    HQueueBufferInput hInput{};
+    HFenceWrapper hFenceWrapper;
+    if (!b2h(input, &hInput, &hFenceWrapper)) {
+        LOG(ERROR) << "queueBuffer: corrupted input.";
+        return UNKNOWN_ERROR;
+    }
+
+    bool converted{};
+    status_t bStatus{};
+    Return<void> transResult = mBase->queueBuffer(
+            static_cast<int32_t>(slot),
+            hInput,
+            [&converted, &bStatus, output](
+                    HStatus hStatus,
+                    HQueueBufferOutput const& hOutput) {
+                converted = h2b(hStatus, &bStatus) && h2b(hOutput, output);
+            });
+
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "queueBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!converted) {
+        LOG(ERROR) << "queueBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::cancelBuffer(int slot, sp<BFence> const& fence) {
+    HFenceWrapper hFenceWrapper;
+    if (!b2h(fence, &hFenceWrapper)) {
+        LOG(ERROR) << "cancelBuffer: corrupted input fence.";
+        return UNKNOWN_ERROR;
+    }
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->cancelBuffer(
+            static_cast<int32_t>(slot),
+            hFenceWrapper.getHandle());
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "cancelBuffer: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "cancelBuffer: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+int H2BGraphicBufferProducer::query(int what, int* value) {
+    int result{};
+    Return<void> transResult = mBase->query(
+            static_cast<int32_t>(what),
+            [&result, value](int32_t r, int32_t v) {
+                result = static_cast<int>(r);
+                *value = static_cast<int>(v);
+            });
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "query: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    return result;
+}
+
+status_t H2BGraphicBufferProducer::connect(
+        sp<IProducerListener> const& listener, int api,
+        bool producerControlledByApp, QueueBufferOutput* output) {
+    HConnectionType hConnectionType;
+    if (!b2h(api, &hConnectionType)) {
+        LOG(ERROR) << "connect: corrupted input connection type.";
+        return UNKNOWN_ERROR;
+    }
+    sp<HProducerListener> hListener = nullptr;
+    if (listener && listener->needsReleaseNotify()) {
+        hListener = new B2HProducerListener(listener);
+        if (!hListener) {
+            LOG(ERROR) << "connect: failed to wrap listener.";
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    bool converted{};
+    status_t bStatus{};
+    Return<void> transResult = mBase->connect(
+            hListener,
+            hConnectionType,
+            producerControlledByApp,
+            [&converted, &bStatus, output](
+                    HStatus hStatus,
+                    HQueueBufferOutput const& hOutput) {
+                converted = h2b(hStatus, &bStatus) && h2b(hOutput, output);
+            });
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "connect: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!converted) {
+        LOG(ERROR) << "connect: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+
+}
+
+status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) {
+    HConnectionType hConnectionType;
+    if (mode == DisconnectMode::AllLocal) {
+        hConnectionType = HConnectionType::CURRENTLY_CONNECTED;
+    } else if (!b2h(api, &hConnectionType)) {
+        LOG(ERROR) << "connect: corrupted input connection type.";
+        return UNKNOWN_ERROR;
+    }
+
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->disconnect(hConnectionType);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "disconnect: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "disconnect: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setSidebandStream(
+        sp<NativeHandle> const& stream) {
+    if (stream) {
+        LOG(INFO) << "setSidebandStream: not supported.";
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+void H2BGraphicBufferProducer::allocateBuffers(
+        uint32_t width, uint32_t height,
+        PixelFormat format, uint64_t usage) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->allocateBuffers(
+            width, height, static_cast<uint32_t>(format), usage);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "allocateBuffer: transaction failed.";
+        return;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "allocateBuffer: corrupted transaction.";
+        return;
+    }
+}
+
+status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->allowAllocation(allow);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "allowAllocation: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "allowAllocation: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setGenerationNumber(
+        uint32_t generationNumber) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->setGenerationNumber(generationNumber);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "setGenerationNumber: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "setGenerationNumber: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+String8 H2BGraphicBufferProducer::getConsumerName() const {
+    String8 bName;
+    Return<void> transResult = mBase->getConsumerName(
+            [&bName](hidl_string const& name) {
+                bName = name.c_str();
+            });
+    return bName;
+}
+
+status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
+    if (sharedBufferMode) {
+        LOG(INFO) << "setSharedBufferMode: not supported.";
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
+    if (autoRefresh) {
+        LOG(INFO) << "setAutoRefresh: not supported.";
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) {
+    status_t bStatus{};
+    Return<HStatus> transResult = mBase->setDequeueTimeout(
+            static_cast<int64_t>(timeout));
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "setDequeueTimeout: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+        LOG(ERROR) << "setDequeueTimeout: corrupted transaction.";
+        return FAILED_TRANSACTION;
+    }
+    return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::getLastQueuedBuffer(
+        sp<GraphicBuffer>*,
+        sp<BFence>*,
+        float[16]) {
+    LOG(INFO) << "getLastQueuedBuffer: not supported.";
+    return INVALID_OPERATION;
+}
+
+void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta*) {
+    LOG(INFO) << "getFrameTimestamps: not supported.";
+}
+
+status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const {
+    Return<uint64_t> transResult = mBase->getUniqueId();
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "getUniqueId: transaction failed.";
+        return FAILED_TRANSACTION;
+    }
+    *outId = static_cast<uint64_t>(transResult);
+    return OK;
+}
+
+status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t*) const {
+    LOG(INFO) << "getConsumerUsage: not supported.";
+    return INVALID_OPERATION;
+}
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
new file mode 100644
index 0000000..b81a357
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BProducerListener@2.0"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+      : CBase{base} {
+}
+
+void H2BProducerListener::onBufferReleased() {
+    if (mBase) {
+        Return<void> transResult = mBase->onBuffersReleased(1);
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "onBuffersReleased: transaction failed.";
+        }
+    }
+}
+
+bool H2BProducerListener::needsReleaseNotify() {
+    return static_cast<bool>(mBase);
+}
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp
new file mode 100644
index 0000000..cbd6cad
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/types.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/native_handle.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <system/window.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+bool b2h(status_t from, HStatus* to,
+         bool* bufferNeedsReallocation, bool* releaseAllBuffers) {
+    switch (from) {
+    case OK:
+        *to = HStatus::OK; break;
+    case NO_MEMORY:
+        *to = HStatus::NO_MEMORY; break;
+    case NO_INIT:
+        *to = HStatus::NO_INIT; break;
+    case BAD_VALUE:
+        *to = HStatus::BAD_VALUE; break;
+    case DEAD_OBJECT:
+        *to = HStatus::DEAD_OBJECT; break;
+    case INVALID_OPERATION:
+        *to = HStatus::INVALID_OPERATION; break;
+    case TIMED_OUT:
+        *to = HStatus::TIMED_OUT; break;
+    case WOULD_BLOCK:
+        *to = HStatus::WOULD_BLOCK; break;
+    case UNKNOWN_ERROR:
+        *to = HStatus::UNKNOWN_ERROR; break;
+    default:
+        using BGBP = ::android::IGraphicBufferProducer;
+        status_t mask =
+                (bufferNeedsReallocation ? BGBP::BUFFER_NEEDS_REALLOCATION : 0)
+                | (releaseAllBuffers ? BGBP::RELEASE_ALL_BUFFERS : 0);
+        if (from & ~mask) {
+            *to = static_cast<HStatus>(from);
+        } else {
+            *to = HStatus::OK;
+            if (bufferNeedsReallocation) {
+                *bufferNeedsReallocation = from & BGBP::BUFFER_NEEDS_REALLOCATION;
+            }
+            if (releaseAllBuffers) {
+                *releaseAllBuffers = from & BGBP::RELEASE_ALL_BUFFERS;
+            }
+        }
+    }
+    return true;
+}
+
+bool h2b(HStatus from, status_t* to) {
+    switch (from) {
+    case HStatus::OK:
+        *to = OK; break;
+    case HStatus::NO_MEMORY:
+        *to = NO_MEMORY; break;
+    case HStatus::NO_INIT:
+        *to = NO_INIT; break;
+    case HStatus::BAD_VALUE:
+        *to = BAD_VALUE; break;
+    case HStatus::DEAD_OBJECT:
+        *to = DEAD_OBJECT; break;
+    case HStatus::INVALID_OPERATION:
+        *to = INVALID_OPERATION; break;
+    case HStatus::TIMED_OUT:
+        *to = TIMED_OUT; break;
+    case HStatus::WOULD_BLOCK:
+        *to = WOULD_BLOCK; break;
+    case HStatus::UNKNOWN_ERROR:
+        *to = UNKNOWN_ERROR; break;
+    default:
+        *to = static_cast<status_t>(from);
+    }
+    return true;
+}
+
+// Fence
+// =====
+
+HFenceWrapper::HFenceWrapper(native_handle_t* h) : mHandle{h} {
+}
+
+HFenceWrapper::~HFenceWrapper() {
+    native_handle_delete(mHandle);
+}
+
+HFenceWrapper& HFenceWrapper::set(native_handle_t* h) {
+    native_handle_delete(mHandle);
+    mHandle = h;
+    return *this;
+}
+
+HFenceWrapper& HFenceWrapper::operator=(native_handle_t* h) {
+    return set(h);
+}
+
+hidl_handle HFenceWrapper::getHandle() const {
+    return hidl_handle{mHandle};
+}
+
+HFenceWrapper::operator hidl_handle() const {
+    return getHandle();
+}
+
+bool b2h(sp<BFence> const& from, HFenceWrapper* to) {
+    if (!from) {
+        to->set(nullptr);
+        return true;
+    }
+    int fenceFd = from->get();
+    if (fenceFd == -1) {
+        to->set(nullptr);
+        return true;
+    }
+    native_handle_t* nh = native_handle_create(1, 0);
+    if (!nh) {
+        return false;
+    }
+    nh->data[0] = fenceFd;
+    to->set(nh);
+    return true;
+}
+
+bool h2b(native_handle_t const* from, sp<BFence>* to) {
+    if (!from || from->numFds == 0) {
+        *to = new ::android::Fence();
+        return true;
+    }
+    if (from->numFds != 1 || from->numInts != 0) {
+        return false;
+    }
+    *to = new BFence(dup(from->data[0]));
+    return true;
+}
+
+// ConnectionType
+// ==============
+
+bool b2h(int from, HConnectionType* to) {
+    *to = static_cast<HConnectionType>(from);
+    switch (from) {
+    case BufferQueueCore::CURRENTLY_CONNECTED_API:
+        *to = HConnectionType::CURRENTLY_CONNECTED; break;
+    case NATIVE_WINDOW_API_EGL:
+        *to = HConnectionType::EGL; break;
+    case NATIVE_WINDOW_API_CPU:
+        *to = HConnectionType::CPU; break;
+    case NATIVE_WINDOW_API_MEDIA:
+        *to = HConnectionType::MEDIA; break;
+    case NATIVE_WINDOW_API_CAMERA:
+        *to = HConnectionType::CAMERA; break;
+    }
+    return true;
+}
+
+bool h2b(HConnectionType from, int* to) {
+    *to = static_cast<int>(from);
+    switch (from) {
+    case HConnectionType::CURRENTLY_CONNECTED:
+        *to = BufferQueueCore::CURRENTLY_CONNECTED_API; break;
+    case HConnectionType::EGL:
+        *to = NATIVE_WINDOW_API_EGL; break;
+    case HConnectionType::CPU:
+        *to = NATIVE_WINDOW_API_CPU; break;
+    case HConnectionType::MEDIA:
+        *to = NATIVE_WINDOW_API_MEDIA; break;
+    case HConnectionType::CAMERA:
+        *to = NATIVE_WINDOW_API_CAMERA; break;
+    }
+    return true;
+}
+
+// Rect
+// ====
+
+bool b2h(BRect const& from, HRect* to) {
+    BRect* dst = reinterpret_cast<BRect*>(to->data());
+    dst->left = from.left;
+    dst->top = from.top;
+    dst->right = from.right;
+    dst->bottom = from.bottom;
+    return true;
+}
+
+bool h2b(HRect const& from, BRect* to) {
+    BRect const* src = reinterpret_cast<BRect const*>(from.data());
+    to->left = src->left;
+    to->top = src->top;
+    to->right = src->right;
+    to->bottom = src->bottom;
+    return true;
+}
+
+// Region
+// ======
+
+bool b2h(BRegion const& from, HRegion* to) {
+    size_t numRects;
+    BRect const* rectArray = from.getArray(&numRects);
+    to->resize(numRects);
+    for (size_t i = 0; i < numRects; ++i) {
+        if (!b2h(rectArray[i], &(*to)[i])) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool h2b(HRegion const& from, BRegion* to) {
+    if (from.size() > 0) {
+        BRect bRect;
+        if (!h2b(from[0], &bRect)) {
+            return false;
+        }
+        to->set(bRect);
+        for (size_t i = 1; i < from.size(); ++i) {
+            if (!h2b(from[i], &bRect)) {
+                return false;
+            }
+            to->addRectUnchecked(
+                    static_cast<int>(bRect.left),
+                    static_cast<int>(bRect.top),
+                    static_cast<int>(bRect.right),
+                    static_cast<int>(bRect.bottom));
+        }
+    } else {
+        to->clear();
+    }
+    return true;
+}
+
+// GraphicBuffer
+// =============
+
+// The handle is not cloned. Its lifetime is tied to the original GraphicBuffer.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+         uint32_t* toGenerationNumber) {
+    if (!from) {
+        return false;
+    }
+    AHardwareBuffer* hwBuffer = from->toAHardwareBuffer();
+    to->nativeHandle.setTo(
+          const_cast<native_handle_t*>(
+              AHardwareBuffer_getNativeHandle(hwBuffer)),
+          false);
+    AHardwareBuffer_describe(
+            hwBuffer,
+            reinterpret_cast<AHardwareBuffer_Desc*>(to->description.data()));
+    if (toGenerationNumber) {
+        *toGenerationNumber = from->getGenerationNumber();
+    }
+    return true;
+}
+
+// The handle is cloned.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to) {
+    AHardwareBuffer_Desc const* desc =
+            reinterpret_cast<AHardwareBuffer_Desc const*>(
+            from.description.data());
+    native_handle_t const* handle = from.nativeHandle;
+    AHardwareBuffer* hwBuffer;
+    if (AHardwareBuffer_createFromHandle(
+            desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+            &hwBuffer) != OK) {
+        return false;
+    }
+    *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer);
+    AHardwareBuffer_release(hwBuffer);
+    return true;
+}
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
diff --git a/libs/gui/bufferqueue/OWNERS b/libs/gui/bufferqueue/OWNERS
new file mode 100644
index 0000000..cbe9317
--- /dev/null
+++ b/libs/gui/bufferqueue/OWNERS
@@ -0,0 +1,5 @@
+chz@google.com
+lajos@google.com
+pawin@google.com
+taklee@google.com
+wonsik@google.com
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
index 23c9909..0e925ce 100644
--- a/libs/gui/include/gui/BufferHubProducer.h
+++ b/libs/gui/include/gui/BufferHubProducer.h
@@ -165,6 +165,10 @@
     // buffers are acquired by the consumer, we can't .
     status_t FreeAllBuffers();
 
+    // Helper function that implements the detachBuffer() call, but assuming |mutex_| has been
+    // locked already.
+    status_t DetachBufferLocked(size_t slot);
+
     // Concreate implementation backed by BufferHubBuffer.
     std::shared_ptr<dvr::ProducerQueue> queue_;
 
@@ -199,10 +203,10 @@
     // requested buffer usage or geometry differs from that of the buffer
     // allocated to a slot.
     struct BufferHubSlot : public BufferSlot {
-        BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
+        BufferHubSlot() : mProducerBuffer(nullptr), mIsReallocating(false) {}
         // BufferSlot comes from android framework, using m prefix to comply with
         // the name convention with the reset of data fields from BufferSlot.
-        std::shared_ptr<dvr::BufferProducer> mBufferProducer;
+        std::shared_ptr<dvr::ProducerBuffer> mProducerBuffer;
         bool mIsReallocating;
     };
     BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity];
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index d108120..7db69ec 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -31,7 +31,7 @@
 class BufferQueueConsumer : public BnGraphicBufferConsumer {
 
 public:
-    BufferQueueConsumer(const sp<BufferQueueCore>& core);
+    explicit BufferQueueConsumer(const sp<BufferQueueCore>& core);
     ~BufferQueueConsumer() override;
 
     // acquireBuffer attempts to acquire ownership of the next pending buffer in
@@ -171,6 +171,9 @@
 
     // End functions required for backwards compatibility
 
+    // Value used to determine if present time is valid.
+    constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second
+
 private:
     sp<BufferQueueCore> mCore;
 
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 537c957..690a85f 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -22,8 +22,6 @@
 #include <gui/BufferSlot.h>
 #include <gui/OccupancyTracker.h>
 
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
 #include <utils/NativeHandle.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
@@ -33,6 +31,8 @@
 
 #include <list>
 #include <set>
+#include <mutex>
+#include <condition_variable>
 
 #define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -40,13 +40,14 @@
 #define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 
-#define ATRACE_BUFFER_INDEX(index)                                   \
-    if (ATRACE_ENABLED()) {                                          \
-        char ___traceBuf[1024];                                      \
-        snprintf(___traceBuf, 1024, "%s: %d",                        \
-                mCore->mConsumerName.string(), (index));             \
-        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);  \
-    }
+#define ATRACE_BUFFER_INDEX(index)                                                         \
+    do {                                                                                   \
+        if (ATRACE_ENABLED()) {                                                            \
+            char ___traceBuf[1024];                                                        \
+            snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
+            android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);                    \
+        }                                                                                  \
+    } while (false)
 
 namespace android {
 
@@ -133,7 +134,7 @@
     bool adjustAvailableSlotsLocked(int delta);
 
     // waitWhileAllocatingLocked blocks until mIsAllocating is false.
-    void waitWhileAllocatingLocked() const;
+    void waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const;
 
 #if DEBUG_ONLY_CODE
     // validateConsistencyLocked ensures that the free lists are in sync with
@@ -144,7 +145,7 @@
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of BufferQueueCore objects. It must be locked whenever any
     // member variable is accessed.
-    mutable Mutex mMutex;
+    mutable std::mutex mMutex;
 
     // mIsAbandoned indicates that the BufferQueue will no longer be used to
     // consume image buffers pushed to it using the IGraphicBufferProducer
@@ -218,13 +219,24 @@
 
     // mDequeueCondition is a condition variable used for dequeueBuffer in
     // synchronous mode.
-    mutable Condition mDequeueCondition;
+    mutable std::condition_variable mDequeueCondition;
 
     // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
     // block. This flag is set during connect when both the producer and
     // consumer are controlled by the application.
     bool mDequeueBufferCannotBlock;
 
+    // mQueueBufferCanDrop indicates whether queueBuffer is allowed to drop
+    // buffers in non-async mode. This flag is set during connect when both the
+    // producer and consumer are controlled by application.
+    bool mQueueBufferCanDrop;
+
+    // mLegacyBufferDrop indicates whether mQueueBufferCanDrop is in effect.
+    // If this flag is set mQueueBufferCanDrop is working as explained. If not
+    // queueBuffer will not drop buffers unless consumer is SurfaceFlinger and
+    // mQueueBufferCanDrop is set.
+    bool mLegacyBufferDrop;
+
     // mDefaultBufferFormat can be set so it will override the buffer format
     // when it isn't specified in dequeueBuffer.
     PixelFormat mDefaultBufferFormat;
@@ -281,7 +293,7 @@
 
     // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
     // becomes false.
-    mutable Condition mIsAllocatingCondition;
+    mutable std::condition_variable mIsAllocatingCondition;
 
     // mAllowAllocation determines whether dequeueBuffer is allowed to allocate
     // new buffers
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 5c7ffb4..d2a47a6 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -29,7 +29,8 @@
 public:
     friend class BufferQueue; // Needed to access binderDied
 
-    BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger = false);
+    explicit BufferQueueProducer(const sp<BufferQueueCore>& core,
+                                 bool consumerIsSurfaceFlinger = false);
     ~BufferQueueProducer() override;
 
     // requestBuffer returns the GraphicBuffer for slot N.
@@ -173,6 +174,9 @@
     // See IGraphicBufferProducer::setDequeueTimeout
     virtual status_t setDequeueTimeout(nsecs_t timeout) override;
 
+    // see IGraphicBufferProducer::setLegacyBufferDrop
+    virtual status_t setLegacyBufferDrop(bool drop);
+
     // See IGraphicBufferProducer::getLastQueuedBuffer
     virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
@@ -210,7 +214,8 @@
         Dequeue,
         Attach,
     };
-    status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const;
+    status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock,
+            int* found) const;
 
     sp<BufferQueueCore> mCore;
 
@@ -242,15 +247,22 @@
     // (mCore->mMutex) is held, a ticket is retained by the producer. After
     // dropping the BufferQueue lock, the producer must wait on the condition
     // variable until the current callback ticket matches its retained ticket.
-    Mutex mCallbackMutex;
+    std::mutex mCallbackMutex;
     int mNextCallbackTicket; // Protected by mCore->mMutex
     int mCurrentCallbackTicket; // Protected by mCallbackMutex
-    Condition mCallbackCondition;
+    std::condition_variable mCallbackCondition;
 
     // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
     // slot is not yet available.
     nsecs_t mDequeueTimeout;
 
+    // If set to true, dequeueBuffer() is currently waiting for buffer allocation to complete.
+    bool mDequeueWaitingForAllocation;
+
+    // Condition variable to signal allocateBuffers() that dequeueBuffer() is no longer waiting for
+    // allocation to complete.
+    std::condition_variable mDequeueWaitingForAllocationCondition;
+
 }; // class BufferQueueProducer
 
 } // namespace android
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index d375611..806fbe8 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -70,7 +70,7 @@
         uint32_t    chromaStep;
 
         LockedBuffer() :
-            data(NULL),
+            data(nullptr),
             width(0),
             height(0),
             format(PIXEL_FORMAT_NONE),
@@ -82,8 +82,8 @@
             dataSpace(HAL_DATASPACE_UNKNOWN),
             frameNumber(0),
             flexFormat(PIXEL_FORMAT_NONE),
-            dataCb(NULL),
-            dataCr(NULL),
+            dataCb(nullptr),
+            dataCr(nullptr),
             chromaStride(0),
             chromaStep(0)
         {}
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 32ce59a..22de751 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -52,13 +52,14 @@
     enum {
         DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
         DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
+        DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
     };
 
     struct Event {
 
         struct Header {
             uint32_t type;
-            uint32_t id;
+            PhysicalDisplayId displayId;
             nsecs_t timestamp __attribute__((aligned(8)));
         };
 
@@ -70,10 +71,15 @@
             bool connected;
         };
 
+        struct Config {
+            int32_t configId;
+        };
+
         Header header;
         union {
             VSync vsync;
             Hotplug hotplug;
+            Config config;
         };
     };
 
@@ -84,7 +90,7 @@
      * or requestNextVsync to receive them.
      * Other events start being delivered immediately.
      */
-    DisplayEventReceiver(
+    explicit DisplayEventReceiver(
             ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
 
     /*
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 9716be4..df02494 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -30,7 +30,6 @@
 
 struct FrameEvents;
 class FrameEventHistoryDelta;
-class String8;
 
 
 // Identifiers for all the events that may be recorded or reported.
@@ -72,7 +71,7 @@
     bool hasDequeueReadyInfo() const;
 
     void checkFencesForCompletion();
-    void dump(String8& outString) const;
+    void dump(std::string& outString) const;
 
     bool valid{false};
     int connectId{0};
@@ -112,7 +111,7 @@
     FrameEvents* getFrame(uint64_t frameNumber);
     FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
     void checkFencesForCompletion();
-    void dump(String8& outString) const;
+    void dump(std::string& outString) const;
 
     static constexpr size_t MAX_FRAME_HISTORY = 8;
 
@@ -311,7 +310,7 @@
 
     // Movable.
     FrameEventHistoryDelta(FrameEventHistoryDelta&& src) = default;
-    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src);
+    FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src) noexcept;
     // Not copyable.
     FrameEventHistoryDelta(const FrameEventHistoryDelta& src) = delete;
     FrameEventHistoryDelta& operator=(
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 71ed3bf..ddd868d 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -140,7 +140,8 @@
 
     // Scale the crop down horizontally or vertically such that it has the
     // same aspect ratio as the buffer does.
-    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
+            uint32_t bufferHeight);
 
     // getTimestamp retrieves the timestamp associated with the texture image
     // set by the most recent call to updateTexImage.
@@ -300,12 +301,11 @@
     // also only creating new EGLImages from buffers when required.
     class EglImage : public LightRefBase<EglImage>  {
     public:
-        EglImage(sp<GraphicBuffer> graphicBuffer);
+        explicit EglImage(sp<GraphicBuffer> graphicBuffer);
 
         // createIfNeeded creates an EGLImage if required (we haven't created
         // one yet, or the EGLDisplay or crop-rect has changed).
         status_t createIfNeeded(EGLDisplay display,
-                                const Rect& cropRect,
                                 bool forceCreate = false);
 
         // This calls glEGLImageTargetTexture2DOES to bind the image to the
@@ -314,7 +314,7 @@
 
         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
         const native_handle* graphicBufferHandle() {
-            return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+            return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
         }
 
     private:
@@ -324,7 +324,7 @@
 
         // createImage creates a new EGLImage from a GraphicBuffer.
         EGLImageKHR createImage(EGLDisplay dpy,
-                const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+                const sp<GraphicBuffer>& graphicBuffer);
 
         // Disallow copying
         EglImage(const EglImage& rhs);
diff --git a/libs/gui/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h
index b020ed9..7aa5432 100644
--- a/libs/gui/include/gui/GuiConfig.h
+++ b/libs/gui/include/gui/GuiConfig.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_GUI_CONFIG_H
 #define ANDROID_GUI_CONFIG_H
 
-#include <utils/String8.h>
+#include <string>
 
 namespace android {
 
 // Append the libgui configuration details to configStr.
-void appendGuiConfigString(String8& configStr);
+void appendGuiConfigString(std::string& configStr);
 
 }; // namespace android
 
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
index 9800602..1e9c3e7 100644
--- a/libs/gui/include/gui/HdrMetadata.h
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <stdint.h>
+#include <vector>
 
 #include <system/graphics.h>
 #include <utils/Flattenable.h>
@@ -26,12 +27,15 @@
 struct HdrMetadata : public LightFlattenable<HdrMetadata> {
     enum Type : uint32_t {
         SMPTE2086 = 1 << 0,
-        CTA861_3  = 1 << 1,
+        CTA861_3 = 1 << 1,
+        HDR10PLUS = 1 << 2,
     };
+
     uint32_t validTypes{0};
 
     android_smpte2086_metadata smpte2086{};
     android_cta861_3_metadata cta8613{};
+    std::vector<uint8_t> hdr10plus{};
 
     // LightFlattenable
     bool isFixedSize() const { return false; }
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 887654e..3dde8c8 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -25,6 +25,7 @@
 
 #include <binder/IInterface.h>
 
+#include <ui/BufferQueueDefs.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
@@ -35,6 +36,7 @@
 
 #include <hidl/HybridInterface.h>
 #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
 
 namespace android {
 // ----------------------------------------------------------------------------
@@ -42,8 +44,6 @@
 class IProducerListener;
 class NativeHandle;
 class Surface;
-typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
-        HGraphicBufferProducer;
 
 /*
  * This class defines the Binder IPC interface for the producer side of
@@ -62,15 +62,24 @@
 class IGraphicBufferProducer : public IInterface
 {
 public:
-    DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer)
+    using HGraphicBufferProducerV1_0 =
+            ::android::hardware::graphics::bufferqueue::V1_0::
+            IGraphicBufferProducer;
+    using HGraphicBufferProducerV2_0 =
+            ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer;
+
+    DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer,
+                                  HGraphicBufferProducerV1_0,
+                                  HGraphicBufferProducerV2_0)
 
     enum {
         // A flag returned by dequeueBuffer when the client needs to call
         // requestBuffer immediately thereafter.
-        BUFFER_NEEDS_REALLOCATION = 0x1,
+        BUFFER_NEEDS_REALLOCATION = BufferQueueDefs::BUFFER_NEEDS_REALLOCATION,
         // A flag returned by dequeueBuffer when all mirrored slots should be
         // released by the client. This flag should always be processed first.
-        RELEASE_ALL_BUFFERS       = 0x2,
+        RELEASE_ALL_BUFFERS       = BufferQueueDefs::RELEASE_ALL_BUFFERS,
     };
 
     enum {
@@ -345,7 +354,7 @@
             *outScalingMode = scalingMode;
             *outTransform = transform;
             *outFence = fence;
-            if (outStickyTransform != NULL) {
+            if (outStickyTransform != nullptr) {
                 *outStickyTransform = stickyTransform;
             }
             if (outGetFrameTimestamps) {
@@ -366,7 +375,6 @@
         const HdrMetadata& getHdrMetadata() const { return hdrMetadata; }
         void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; }
 
-    private:
         int64_t timestamp{0};
         int isAutoTimestamp{0};
         android_dataspace dataSpace{HAL_DATASPACE_UNKNOWN};
@@ -584,12 +592,20 @@
     // non-blocking mode and its corresponding spare buffer (which is used to
     // ensure a buffer is always available).
     //
+    // Note well: queueBuffer will stop buffer dropping behavior if timeout is
+    // strictly positive. If timeout is zero or negative, previous buffer
+    // dropping behavior will not be changed.
+    //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * BAD_VALUE - Failure to adjust the number of available slots. This can
     //               happen because of trying to allocate/deallocate the async
     //               buffer.
     virtual status_t setDequeueTimeout(nsecs_t timeout) = 0;
 
+    // Used to enable/disable buffer drop behavior of queueBuffer.
+    // If it's not used, legacy drop behavior will be retained.
+    virtual status_t setLegacyBufferDrop(bool drop);
+
     // Returns the last queued buffer along with a fence which must signal
     // before the contents of the buffer are read. If there are no buffers in
     // the queue, outBuffer will be populated with nullptr and outFence will be
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index e808bd3..a13d8e4 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_GUI_IPRODUCERLISTENER_H
 #define ANDROID_GUI_IPRODUCERLISTENER_H
 
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
 #include <binder/IInterface.h>
-
+#include <hidl/HybridInterface.h>
 #include <utils/RefBase.h>
 
 namespace android {
@@ -47,7 +49,14 @@
 class IProducerListener : public ProducerListener, public IInterface
 {
 public:
-    DECLARE_META_INTERFACE(ProducerListener)
+    using HProducerListener1 =
+            ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener;
+    using HProducerListener2 =
+            ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener;
+    DECLARE_HYBRID_META_INTERFACE(
+            ProducerListener,
+            HProducerListener1,
+            HProducerListener2)
 };
 
 class BnProducerListener : public BnInterface<IProducerListener>
diff --git a/libs/gui/include/gui/IRegionSamplingListener.h b/libs/gui/include/gui/IRegionSamplingListener.h
new file mode 100644
index 0000000..1803d9a
--- /dev/null
+++ b/libs/gui/include/gui/IRegionSamplingListener.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
+namespace android {
+
+class IRegionSamplingListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(RegionSamplingListener)
+
+    virtual void onSampleCollected(float medianLuma) = 0;
+};
+
+class BnRegionSamplingListener : public SafeBnInterface<IRegionSamplingListener> {
+public:
+    BnRegionSamplingListener()
+          : SafeBnInterface<IRegionSamplingListener>("BnRegionSamplingListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0db21a5..e2f7736 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -20,32 +20,42 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/RefBase.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+#include <gui/ITransactionCompletedListener.h>
+
+#include <ui/ConfigStoreTypes.h>
+#include <ui/DisplayedFrameStats.h>
+#include <ui/FrameStats.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/PixelFormat.h>
+
 #include <utils/Errors.h>
+#include <utils/RefBase.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
 
-#include <binder/IInterface.h>
-
-#include <ui/FrameStats.h>
-#include <ui/PixelFormat.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/GraphicTypes.h>
-
+#include <optional>
+#include <unordered_set>
 #include <vector>
 
 namespace android {
 // ----------------------------------------------------------------------------
 
+struct client_cache_t;
 struct ComposerState;
 struct DisplayState;
 struct DisplayInfo;
 struct DisplayStatInfo;
+struct InputWindowCommands;
 class LayerDebugInfo;
 class HdrCapabilities;
 class IDisplayEventConnection;
 class IGraphicBufferProducer;
 class ISurfaceComposerClient;
+class IRegionSamplingListener;
 class Rect;
 enum class FrameEvent;
 
@@ -68,11 +78,6 @@
         eEarlyWakeup = 0x04
     };
 
-    enum {
-        eDisplayIdMain = 0,
-        eDisplayIdHdmi = 1
-    };
-
     enum Rotation {
         eRotateNone = 0,
         eRotate90   = 1,
@@ -85,22 +90,11 @@
         eVsyncSourceSurfaceFlinger = 1
     };
 
-    /* create connection with surface flinger, requires
-     * ACCESS_SURFACE_FLINGER permission
+    /*
+     * Create a connection with SurfaceFlinger.
      */
     virtual sp<ISurfaceComposerClient> createConnection() = 0;
 
-    /** create a scoped connection with surface flinger.
-     * Surfaces produced with this connection will act
-     * as children of the passed in GBP. That is to say
-     * SurfaceFlinger will draw them relative and confined to
-     * drawing of buffers from the layer associated with parent.
-     * As this is graphically equivalent in reach to just drawing
-     * pixels into the parent buffers, it requires no special permission.
-     */
-    virtual sp<ISurfaceComposerClient> createScopedConnection(
-            const sp<IGraphicBufferProducer>& parent) = 0;
-
     /* return an IDisplayEventConnection */
     virtual sp<IDisplayEventConnection> createDisplayEventConnection(
             VsyncSource vsyncSource = eVsyncSourceApp) = 0;
@@ -116,14 +110,35 @@
      */
     virtual void destroyDisplay(const sp<IBinder>& display) = 0;
 
-    /* get the token for the existing default displays. possible values
-     * for id are eDisplayIdMain and eDisplayIdHdmi.
+    /* get stable IDs for connected physical displays.
      */
-    virtual sp<IBinder> getBuiltInDisplay(int32_t id) = 0;
+    virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
+
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    std::optional<PhysicalDisplayId> getInternalDisplayId() const {
+        const auto displayIds = getPhysicalDisplayIds();
+        return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
+    }
+
+    /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a
+     * DisplayEventReceiver hotplug event.
+     */
+    virtual sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0;
+
+    // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
+    sp<IBinder> getInternalDisplayToken() const {
+        const auto displayId = getInternalDisplayId();
+        return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+    }
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual void setTransactionState(const Vector<ComposerState>& state,
-            const Vector<DisplayState>& displays, uint32_t flags) = 0;
+                                     const Vector<DisplayState>& displays, uint32_t flags,
+                                     const sp<IBinder>& applyToken,
+                                     const InputWindowCommands& inputWindowCommands,
+                                     int64_t desiredPresentTime,
+                                     const client_cache_t& uncacheBuffer,
+                                     const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -157,9 +172,6 @@
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats) = 0;
 
-    /* returns display viewport information of the given display */
-    virtual status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport) = 0;
-
     /* indicates which of the configurations returned by getDisplayInfo is
      * currently active */
     virtual int getActiveConfig(const sp<IBinder>& display) = 0;
@@ -170,36 +182,103 @@
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
             Vector<ui::ColorMode>* outColorModes) = 0;
+    virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+            ui::DisplayPrimaries& primaries) = 0;
     virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
             ui::ColorMode colorMode) = 0;
 
-    /* Capture the specified screen. requires READ_FRAME_BUFFER permission
-     * This function will fail if there is a secure window on screen.
+    /**
+     * Capture the specified screen. This requires READ_FRAME_BUFFER
+     * permission.  This function will fail if there is a secure window on
+     * screen.
+     *
+     * This function can capture a subregion (the source crop) of the screen.
+     * The subregion can be optionally rotated.  It will also be scaled to
+     * match the size of the output buffer.
+     *
+     * reqDataspace and reqPixelFormat specify the data space and pixel format
+     * of the buffer. The caller should pick the data space and pixel format
+     * that it can consume.
+     *
+     * sourceCrop is the crop on the logical display.
+     *
+     * reqWidth and reqHeight specifies the size of the buffer.  When either
+     * of them is 0, they are set to the size of the logical display viewport.
+     *
+     * When useIdentityTransform is true, layer transformations are disabled.
+     *
+     * rotation specifies the rotation of the source crop (and the pixels in
+     * it) around its center.
      */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   bool& outCapturedSecureLayers, Rect sourceCrop,
-                                   uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
-                                   int32_t maxLayerZ, bool useIdentityTransform,
+                                   bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                                    Rotation rotation = eRotateNone,
                                    bool captureSecureLayers = false) = 0;
-
+    /**
+     * Capture the specified screen. This requires READ_FRAME_BUFFER
+     * permission.  This function will fail if there is a secure window on
+     * screen.
+     *
+     * This function can capture a subregion (the source crop) of the screen
+     * into an sRGB buffer with RGBA_8888 pixel format.
+     * The subregion can be optionally rotated.  It will also be scaled to
+     * match the size of the output buffer.
+     *
+     * At the moment, sourceCrop is ignored and is always set to the visible
+     * region (projected display viewport) of the screen.
+     *
+     * reqWidth and reqHeight specifies the size of the buffer.  When either
+     * of them is 0, they are set to the size of the logical display viewport.
+     *
+     * When useIdentityTransform is true, layer transformations are disabled.
+     *
+     * rotation specifies the rotation of the source crop (and the pixels in
+     * it) around its center.
+     */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   Rect sourceCrop,
-                                   uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
-                                   int32_t maxLayerZ, bool useIdentityTransform,
-                                   Rotation rotation = eRotateNone,
-                                   bool captureSecureLayers = false) {
-      bool ignored;
-      return captureScreen(display, outBuffer, ignored, sourceCrop, reqWidth, reqHeight, minLayerZ,
-                           maxLayerZ, useIdentityTransform, rotation, captureSecureLayers);
+                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   bool useIdentityTransform, Rotation rotation = eRotateNone) {
+        bool outIgnored;
+        return captureScreen(display, outBuffer, outIgnored, ui::Dataspace::V0_SRGB,
+                             ui::PixelFormat::RGBA_8888, sourceCrop, reqWidth, reqHeight,
+                             useIdentityTransform, rotation);
     }
+
+    virtual status_t captureScreen(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
+                                   sp<GraphicBuffer>* outBuffer) = 0;
+
+    template <class AA>
+    struct SpHash {
+        size_t operator()(const sp<AA>& k) const { return std::hash<AA*>()(k.get()); }
+    };
+
     /**
      * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+     *
+     * reqDataspace and reqPixelFormat specify the data space and pixel format
+     * of the buffer. The caller should pick the data space and pixel format
+     * that it can consume.
      */
-    virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
-                                   sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
-                                   float frameScale = 1.0, bool childrenOnly = false) = 0;
+    virtual status_t captureLayers(
+            const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
+            const Rect& sourceCrop,
+            const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeHandles,
+            float frameScale = 1.0, bool childrenOnly = false) = 0;
+
+    /**
+     * Capture a subtree of the layer hierarchy into an sRGB buffer with RGBA_8888 pixel format,
+     * potentially ignoring the root node.
+     */
+    status_t captureLayers(const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
+                           const Rect& sourceCrop, float frameScale = 1.0,
+                           bool childrenOnly = false) {
+        return captureLayers(layerHandleBinder, outBuffer, ui::Dataspace::V0_SRGB,
+                             ui::PixelFormat::RGBA_8888, sourceCrop, {}, frameScale, childrenOnly);
+    }
 
     /* Clears the frame statistics for animations.
      *
@@ -229,29 +308,156 @@
      * Requires the ACCESS_SURFACE_FLINGER permission.
      */
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
+
+    virtual status_t getColorManagement(bool* outGetColorManagement) const = 0;
+
+    /* Gets the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                              ui::PixelFormat* defaultPixelFormat,
+                                              ui::Dataspace* wideColorGamutDataspace,
+                                              ui::PixelFormat* wideColorGamutPixelFormat) const = 0;
+    /*
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+                                                           ui::PixelFormat* outFormat,
+                                                           ui::Dataspace* outDataspace,
+                                                           uint8_t* outComponentMask) const = 0;
+
+    /* Turns on the color sampling engine on the display.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                      uint8_t componentMask,
+                                                      uint64_t maxFrames) const = 0;
+
+    /* Returns statistics on the color profile of the last frame displayed for a given display
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const = 0;
+
+    /*
+     * Gets whether SurfaceFlinger can support protected content in GPU composition.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
+
+    /*
+     * Queries whether the given display is a wide color display.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t isWideColorDisplay(const sp<IBinder>& token,
+                                        bool* outIsWideColorDisplay) const = 0;
+
+    /* Registers a listener to stream median luma updates from SurfaceFlinger.
+     *
+     * The sampling area is bounded by both samplingArea and the given stopLayerHandle
+     * (i.e., only layers behind the stop layer will be captured and sampled).
+     *
+     * Multiple listeners may be provided so long as they have independent listeners.
+     * If multiple listeners are provided, the effective sampling region for each listener will
+     * be bounded by whichever stop layer has a lower Z value.
+     *
+     * Requires the same permissions as captureLayers and captureScreen.
+     */
+    virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+                                               const sp<IBinder>& stopLayerHandle,
+                                               const sp<IRegionSamplingListener>& listener) = 0;
+
+    /*
+     * Removes a listener that was streaming median luma updates from SurfaceFlinger.
+     */
+    virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
+
+    /*
+     * Sets the allowed display configurations to be used.
+     * The allowedConfigs in a vector of indexes corresponding to the configurations
+     * returned from getDisplayConfigs().
+     */
+    virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              const std::vector<int32_t>& allowedConfigs) = 0;
+
+    /*
+     * Returns the allowed display configurations currently set.
+     * The allowedConfigs in a vector of indexes corresponding to the configurations
+     * returned from getDisplayConfigs().
+     */
+    virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                              std::vector<int32_t>* outAllowedConfigs) = 0;
+    /*
+     * Gets whether brightness operations are supported on a display.
+     *
+     * displayToken
+     *      The token of the display.
+     * outSupport
+     *      An output parameter for whether brightness operations are supported.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND if the display is invalid, or
+     *      BAD_VALUE      if the output parameter is invalid.
+     */
+    virtual status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
+                                                 bool* outSupport) const = 0;
+
+    /*
+     * Sets the brightness of a display.
+     *
+     * displayToken
+     *      The token of the display whose brightness is set.
+     * brightness
+     *      A number between 0.0f (minimum brightness) and 1.0 (maximum brightness), or -1.0f to
+     *      turn the backlight off.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND    if the display is invalid, or
+     *      BAD_VALUE         if the brightness is invalid, or
+     *      INVALID_OPERATION if brightness operations are not supported.
+     */
+    virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
+                                          float brightness) const = 0;
+
+    /*
+     * Sends a power hint to the composer. This function is asynchronous.
+     *
+     * hintId
+     *      hint id according to android::hardware::power::V1_0::PowerHint
+     *
+     * Returns NO_ERROR upon success.
+     */
+    virtual status_t notifyPowerHint(int32_t hintId) = 0;
 };
 
 // ----------------------------------------------------------------------------
 
 class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
 public:
-    enum {
+    enum ISurfaceComposerTag {
         // Note: BOOT_FINISHED must remain this value, it is called from
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
-        UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
+        CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check
         CREATE_DISPLAY_EVENT_CONNECTION,
         CREATE_DISPLAY,
         DESTROY_DISPLAY,
-        GET_BUILT_IN_DISPLAY,
+        GET_PHYSICAL_DISPLAY_TOKEN,
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
         GET_SUPPORTED_FRAME_TIMESTAMPS,
         GET_DISPLAY_CONFIGS,
         GET_ACTIVE_CONFIG,
         SET_ACTIVE_CONFIG,
-        CONNECT_DISPLAY,
+        CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
         CAPTURE_SCREEN,
         CAPTURE_LAYERS,
         CLEAR_ANIMATION_FRAME_STATS,
@@ -265,8 +471,24 @@
         ENABLE_VSYNC_INJECTIONS,
         INJECT_VSYNC,
         GET_LAYER_DEBUG_INFO,
-        CREATE_SCOPED_CONNECTION,
-        GET_DISPLAY_VIEWPORT
+        GET_COMPOSITION_PREFERENCE,
+        GET_COLOR_MANAGEMENT,
+        GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+        SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
+        GET_DISPLAYED_CONTENT_SAMPLE,
+        GET_PROTECTED_CONTENT_SUPPORT,
+        IS_WIDE_COLOR_DISPLAY,
+        GET_DISPLAY_NATIVE_PRIMARIES,
+        GET_PHYSICAL_DISPLAY_IDS,
+        ADD_REGION_SAMPLING_LISTENER,
+        REMOVE_REGION_SAMPLING_LISTENER,
+        SET_ALLOWED_DISPLAY_CONFIGS,
+        GET_ALLOWED_DISPLAY_CONFIGS,
+        GET_DISPLAY_BRIGHTNESS_SUPPORT,
+        SET_DISPLAY_BRIGHTNESS,
+        CAPTURE_SCREEN_BY_ID,
+        NOTIFY_POWER_HINT,
+        // Always append new enum to the end.
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 8dfc99a..32ac9e8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -18,8 +18,11 @@
 
 #include <binder/IInterface.h>
 #include <binder/SafeInterface.h>
+#include <gui/LayerMetadata.h>
 #include <ui/PixelFormat.h>
 
+#include <unordered_map>
+
 namespace android {
 
 class FrameStats;
@@ -40,8 +43,10 @@
         eProtectedByDRM = 0x00001000,
         eCursorWindow = 0x00002000,
 
-        eFXSurfaceNormal = 0x00000000,
+        eFXSurfaceBufferQueue = 0x00000000,
         eFXSurfaceColor = 0x00020000,
+        eFXSurfaceBufferState = 0x00040000,
+        eFXSurfaceContainer = 0x00080000,
         eFXSurfaceMask = 0x000F0000,
     };
 
@@ -49,14 +54,18 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
-                                   uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
-                                   int32_t ownerUid, sp<IBinder>* handle,
+                                   uint32_t flags, const sp<IBinder>& parent,
+                                   LayerMetadata metadata, sp<IBinder>* handle,
                                    sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
-    virtual status_t destroySurface(const sp<IBinder>& handle) = 0;
+    virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+                                             PixelFormat format, uint32_t flags,
+                                             const sp<IGraphicBufferProducer>& parent,
+                                             LayerMetadata metadata, sp<IBinder>* handle,
+                                             sp<IGraphicBufferProducer>* gbp) = 0;
 
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
new file mode 100644
index 0000000..774ad46
--- /dev/null
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/SafeInterface.h>
+
+#include <ui/Fence.h>
+#include <utils/Timers.h>
+
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+
+class ITransactionCompletedListener;
+
+using CallbackId = int64_t;
+
+class SurfaceStats : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    SurfaceStats() = default;
+    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
+          : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
+
+    sp<IBinder> surfaceControl;
+    nsecs_t acquireTime = -1;
+    sp<Fence> previousReleaseFence;
+};
+
+class TransactionStats : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    TransactionStats() = default;
+    TransactionStats(const std::vector<CallbackId>& ids) : callbackIds(ids) {}
+    TransactionStats(const std::unordered_set<CallbackId>& ids)
+          : callbackIds(ids.begin(), ids.end()) {}
+    TransactionStats(const std::vector<CallbackId>& ids, nsecs_t latch, const sp<Fence>& present,
+                     const std::vector<SurfaceStats>& surfaces)
+          : callbackIds(ids), latchTime(latch), presentFence(present), surfaceStats(surfaces) {}
+
+    std::vector<CallbackId> callbackIds;
+    nsecs_t latchTime = -1;
+    sp<Fence> presentFence = nullptr;
+    std::vector<SurfaceStats> surfaceStats;
+};
+
+class ListenerStats : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener,
+                                     const std::unordered_set<CallbackId>& callbackIds);
+
+    sp<ITransactionCompletedListener> listener;
+    std::vector<TransactionStats> transactionStats;
+};
+
+class ITransactionCompletedListener : public IInterface {
+public:
+    DECLARE_META_INTERFACE(TransactionCompletedListener)
+
+    virtual void onTransactionCompleted(ListenerStats stats) = 0;
+};
+
+class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
+public:
+    BnTransactionCompletedListener()
+          : SafeBnInterface<ITransactionCompletedListener>("BnTransactionCompletedListener") {}
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t flags = 0) override;
+};
+
+class ListenerCallbacks {
+public:
+    ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+                      const std::unordered_set<CallbackId>& callbacks)
+          : transactionCompletedListener(listener),
+            callbackIds(callbacks.begin(), callbacks.end()) {}
+
+    ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+                      const std::vector<CallbackId>& ids)
+          : transactionCompletedListener(listener), callbackIds(ids) {}
+
+    sp<ITransactionCompletedListener> transactionCompletedListener;
+    std::vector<CallbackId> callbackIds;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 92bd8c5..66a7b4d 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -52,7 +52,6 @@
     int32_t mWidth = -1;
     int32_t mHeight = -1;
     Rect mCrop = Rect::INVALID_RECT;
-    Rect mFinalCrop = Rect::INVALID_RECT;
     half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
     uint32_t mFlags = 0;
     PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
new file mode 100644
index 0000000..47f0ced
--- /dev/null
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcelable.h>
+
+#include <unordered_map>
+
+namespace android {
+
+enum { METADATA_OWNER_UID = 1, METADATA_WINDOW_TYPE = 2, METADATA_TASK_ID = 3 };
+
+struct LayerMetadata : public Parcelable {
+    std::unordered_map<uint32_t, std::vector<uint8_t>> mMap;
+
+    LayerMetadata();
+    LayerMetadata(const LayerMetadata& other);
+    LayerMetadata(LayerMetadata&& other);
+    explicit LayerMetadata(std::unordered_map<uint32_t, std::vector<uint8_t>> map);
+    LayerMetadata& operator=(const LayerMetadata& other);
+    LayerMetadata& operator=(LayerMetadata&& other);
+
+    // Merges other into this LayerMetadata. If eraseEmpty is true, any entries in
+    // in this whose keys are paired with empty values in other will be erased.
+    bool merge(const LayerMetadata& other, bool eraseEmpty = false);
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    bool has(uint32_t key) const;
+    int32_t getInt32(uint32_t key, int32_t fallback) const;
+    void setInt32(uint32_t key, int32_t value);
+
+    std::string itemToString(uint32_t key, const char* separator) const;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 788962e..f438eb3 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -22,127 +22,211 @@
 
 #include <utils/Errors.h>
 
-#include <ui/Region.h>
-#include <ui/Rect.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <math/mat4.h>
+
+#ifndef NO_INPUT
+#include <input/InputWindow.h>
+#endif
+
+#include <gui/LayerMetadata.h>
 #include <math/vec3.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 namespace android {
 
 class Parcel;
 class ISurfaceComposerClient;
 
+struct client_cache_t {
+    wp<IBinder> token = nullptr;
+    uint64_t id;
+
+    bool operator==(const client_cache_t& other) const { return id == other.id; }
+
+    bool isValid() const { return token != nullptr; }
+};
+
 /*
  * Used to communicate layer information between SurfaceFlinger and its clients.
  */
 struct layer_state_t {
-
-
     enum {
-        eLayerHidden        = 0x01,     // SURFACE_HIDDEN in SurfaceControl.java
-        eLayerOpaque        = 0x02,     // SURFACE_OPAQUE
-        eLayerSecure        = 0x80,     // SECURE
+        eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
+        eLayerOpaque = 0x02, // SURFACE_OPAQUE
+        eLayerSecure = 0x80, // SECURE
     };
 
     enum {
-        ePositionChanged            = 0x00000001,
-        eLayerChanged               = 0x00000002,
-        eSizeChanged                = 0x00000004,
-        eAlphaChanged               = 0x00000008,
-        eMatrixChanged              = 0x00000010,
-        eTransparentRegionChanged   = 0x00000020,
-        eFlagsChanged               = 0x00000040,
-        eLayerStackChanged          = 0x00000080,
-        eCropChanged                = 0x00000100,
-        eDeferTransaction           = 0x00000200,
-        eFinalCropChanged           = 0x00000400,
-        eOverrideScalingModeChanged = 0x00000800,
-        eGeometryAppliesWithResize  = 0x00001000,
-        eReparentChildren           = 0x00002000,
-        eDetachChildren             = 0x00004000,
-        eRelativeLayerChanged       = 0x00008000,
-        eReparent                   = 0x00010000,
-        eColorChanged               = 0x00020000,
-        eDestroySurface             = 0x00040000
+        ePositionChanged = 0x00000001,
+        eLayerChanged = 0x00000002,
+        eSizeChanged = 0x00000004,
+        eAlphaChanged = 0x00000008,
+        eMatrixChanged = 0x00000010,
+        eTransparentRegionChanged = 0x00000020,
+        eFlagsChanged = 0x00000040,
+        eLayerStackChanged = 0x00000080,
+        eCropChanged_legacy = 0x00000100,
+        eDeferTransaction_legacy = 0x00000200,
+        eOverrideScalingModeChanged = 0x00000400,
+        eGeometryAppliesWithResize = 0x00000800,
+        eReparentChildren = 0x00001000,
+        eDetachChildren = 0x00002000,
+        eRelativeLayerChanged = 0x00004000,
+        eReparent = 0x00008000,
+        eColorChanged = 0x00010000,
+        eDestroySurface = 0x00020000,
+        eTransformChanged = 0x00040000,
+        eTransformToDisplayInverseChanged = 0x00080000,
+        eCropChanged = 0x00100000,
+        eBufferChanged = 0x00200000,
+        eAcquireFenceChanged = 0x00400000,
+        eDataspaceChanged = 0x00800000,
+        eHdrMetadataChanged = 0x01000000,
+        eSurfaceDamageRegionChanged = 0x02000000,
+        eApiChanged = 0x04000000,
+        eSidebandStreamChanged = 0x08000000,
+        eColorTransformChanged = 0x10000000,
+        eHasListenerCallbacksChanged = 0x20000000,
+        eInputInfoChanged = 0x40000000,
+        eCornerRadiusChanged = 0x80000000,
+        eFrameChanged = 0x1'00000000,
+        eCachedBufferChanged = 0x2'00000000,
+        eBackgroundColorChanged = 0x4'00000000,
+        eMetadataChanged = 0x8'00000000,
+        eColorSpaceAgnosticChanged = 0x10'00000000,
     };
 
     layer_state_t()
-        :   what(0),
-            x(0), y(0), z(0), w(0), h(0), layerStack(0),
-            alpha(0), flags(0), mask(0),
-            reserved(0), crop(Rect::INVALID_RECT),
-            finalCrop(Rect::INVALID_RECT), frameNumber(0),
-            overrideScalingMode(-1)
-    {
+          : what(0),
+            x(0),
+            y(0),
+            z(0),
+            w(0),
+            h(0),
+            layerStack(0),
+            alpha(0),
+            flags(0),
+            mask(0),
+            reserved(0),
+            crop_legacy(Rect::INVALID_RECT),
+            cornerRadius(0.0f),
+            frameNumber_legacy(0),
+            overrideScalingMode(-1),
+            transform(0),
+            transformToDisplayInverse(false),
+            crop(Rect::INVALID_RECT),
+            frame(Rect::INVALID_RECT),
+            dataspace(ui::Dataspace::UNKNOWN),
+            surfaceDamageRegion(),
+            api(-1),
+            colorTransform(mat4()),
+            hasListenerCallbacks(false),
+            bgColorAlpha(0),
+            bgColorDataspace(ui::Dataspace::UNKNOWN),
+            colorSpaceAgnostic(false) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
+        hdrMetadata.validTypes = 0;
     }
 
     void merge(const layer_state_t& other);
-    status_t    write(Parcel& output) const;
-    status_t    read(const Parcel& input);
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
 
-            struct matrix22_t {
-                float   dsdx{0};
-                float   dtdx{0};
-                float   dtdy{0};
-                float   dsdy{0};
-            };
-            sp<IBinder>     surface;
-            uint32_t        what;
-            float           x;
-            float           y;
-            int32_t         z;
-            uint32_t        w;
-            uint32_t        h;
-            uint32_t        layerStack;
-            float           alpha;
-            uint8_t         flags;
-            uint8_t         mask;
-            uint8_t         reserved;
-            matrix22_t      matrix;
-            Rect            crop;
-            Rect            finalCrop;
-            sp<IBinder>     barrierHandle;
-            sp<IBinder>     reparentHandle;
-            uint64_t        frameNumber;
-            int32_t         overrideScalingMode;
+    struct matrix22_t {
+        float dsdx{0};
+        float dtdx{0};
+        float dtdy{0};
+        float dsdy{0};
+    };
+    sp<IBinder> surface;
+    uint64_t what;
+    float x;
+    float y;
+    int32_t z;
+    uint32_t w;
+    uint32_t h;
+    uint32_t layerStack;
+    float alpha;
+    uint8_t flags;
+    uint8_t mask;
+    uint8_t reserved;
+    matrix22_t matrix;
+    Rect crop_legacy;
+    float cornerRadius;
+    sp<IBinder> barrierHandle_legacy;
+    sp<IBinder> reparentHandle;
+    uint64_t frameNumber_legacy;
+    int32_t overrideScalingMode;
 
-            sp<IGraphicBufferProducer> barrierGbp;
+    sp<IGraphicBufferProducer> barrierGbp_legacy;
 
-            sp<IBinder>     relativeLayerHandle;
+    sp<IBinder> relativeLayerHandle;
 
-            sp<IBinder>     parentHandleForChild;
+    sp<IBinder> parentHandleForChild;
 
-            half3           color;
+    half3 color;
 
-            // non POD must be last. see write/read
-            Region          transparentRegion;
+    // non POD must be last. see write/read
+    Region transparentRegion;
+
+    uint32_t transform;
+    bool transformToDisplayInverse;
+    Rect crop;
+    Rect frame;
+    sp<GraphicBuffer> buffer;
+    sp<Fence> acquireFence;
+    ui::Dataspace dataspace;
+    HdrMetadata hdrMetadata;
+    Region surfaceDamageRegion;
+    int32_t api;
+    sp<NativeHandle> sidebandStream;
+    mat4 colorTransform;
+
+    bool hasListenerCallbacks;
+#ifndef NO_INPUT
+    InputWindowInfo inputInfo;
+#endif
+
+    client_cache_t cachedBuffer;
+
+    LayerMetadata metadata;
+
+    // The following refer to the alpha, and dataspace, respectively of
+    // the background color layer
+    float bgColorAlpha;
+    ui::Dataspace bgColorDataspace;
+
+    // A color space agnostic layer means the color of this layer can be
+    // interpreted in any color space.
+    bool colorSpaceAgnostic;
 };
 
 struct ComposerState {
     sp<ISurfaceComposerClient> client;
     layer_state_t state;
-    status_t    write(Parcel& output) const;
-    status_t    read(const Parcel& input);
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
 };
 
 struct DisplayState {
-
     enum {
-        eOrientationDefault     = 0,
-        eOrientation90          = 1,
-        eOrientation180         = 2,
-        eOrientation270         = 3,
-        eOrientationUnchanged   = 4,
-        eOrientationSwapMask    = 0x01
+        eOrientationDefault = 0,
+        eOrientation90 = 1,
+        eOrientation180 = 2,
+        eOrientation270 = 3,
+        eOrientationUnchanged = 4,
+        eOrientationSwapMask = 0x01
     };
 
     enum {
-        eSurfaceChanged             = 0x01,
-        eLayerStackChanged          = 0x02,
-        eDisplayProjectionChanged   = 0x04,
-        eDisplaySizeChanged         = 0x08
+        eSurfaceChanged = 0x01,
+        eLayerStackChanged = 0x02,
+        eDisplayProjectionChanged = 0x04,
+        eDisplaySizeChanged = 0x08
     };
 
     DisplayState();
@@ -152,29 +236,55 @@
     sp<IBinder> token;
     sp<IGraphicBufferProducer> surface;
     uint32_t layerStack;
+
+    // These states define how layers are projected onto the physical display.
+    //
+    // Layers are first clipped to `viewport'.  They are then translated and
+    // scaled from `viewport' to `frame'.  Finally, they are rotated according
+    // to `orientation', `width', and `height'.
+    //
+    // For example, assume viewport is Rect(0, 0, 200, 100), frame is Rect(20,
+    // 10, 420, 210), and the size of the display is WxH.  When orientation is
+    // 0, layers will be scaled by a factor of 2 and translated by (20, 10).
+    // When orientation is 1, layers will be additionally rotated by 90
+    // degrees around the origin clockwise and translated by (W, 0).
     uint32_t orientation;
     Rect viewport;
     Rect frame;
+
     uint32_t width, height;
+
     status_t write(Parcel& output) const;
     status_t read(const Parcel& input);
 };
 
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+struct InputWindowCommands {
+    struct TransferTouchFocusCommand {
+        sp<IBinder> fromToken;
+        sp<IBinder> toToken;
+    };
+
+    std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
+    bool syncInputWindows{false};
+
+    void merge(const InputWindowCommands& other);
+    void clear();
+    void write(Parcel& output) const;
+    void 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;
+    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) {
+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/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
index 8f47eb4..b4eef29 100644
--- a/libs/gui/include/gui/StreamSplitter.h
+++ b/libs/gui/include/gui/StreamSplitter.h
@@ -128,7 +128,7 @@
 
     class BufferTracker : public LightRefBase<BufferTracker> {
     public:
-        BufferTracker(const sp<GraphicBuffer>& buffer);
+        explicit BufferTracker(const sp<GraphicBuffer>& buffer);
 
         const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
         const sp<Fence>& getMergedFence() const { return mMergedFence; }
@@ -154,7 +154,7 @@
     };
 
     // Only called from createSplitter
-    StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue);
+    explicit StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue);
 
     // Must be accessed through RefBase
     virtual ~StreamSplitter();
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 9aeafae..0c471bb 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -80,7 +80,7 @@
     /* convenience function to check that the given surface is non NULL as
      * well as its IGraphicBufferProducer */
     static bool isValid(const sp<Surface>& surface) {
-        return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
+        return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr;
     }
 
     /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
@@ -218,6 +218,7 @@
     int dispatchSetBuffersDataSpace(va_list args);
     int dispatchSetBuffersSmpte2086Metadata(va_list args);
     int dispatchSetBuffersCta8613Metadata(va_list args);
+    int dispatchSetBuffersHdr10PlusMetadata(va_list args);
     int dispatchSetSurfaceDamage(va_list args);
     int dispatchSetSharedBufferMode(va_list args);
     int dispatchSetAutoRefresh(va_list args);
@@ -229,6 +230,7 @@
     int dispatchGetWideColorSupport(va_list args);
     int dispatchGetHdrSupport(va_list args);
     int dispatchGetConsumerUsage64(va_list args);
+    bool transformToDisplayInverse();
 
 protected:
     virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -249,6 +251,7 @@
     virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
     virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
     virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
+    virtual int setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata);
     virtual int setCrop(Rect const* rect);
     virtual int setUsage(uint64_t reqUsage);
     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 49bb687..0e17c7b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,7 +19,9 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <set>
 #include <unordered_map>
+#include <unordered_set>
 
 #include <binder/IBinder.h>
 
@@ -28,14 +30,18 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include <ui/ConfigStoreTypes.h>
+#include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
 #include <gui/CpuConsumer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerState.h>
 #include <gui/SurfaceControl.h>
 #include <math/vec3.h>
-#include <gui/LayerState.h>
 
 namespace android {
 
@@ -45,17 +51,37 @@
 class HdrCapabilities;
 class ISurfaceComposerClient;
 class IGraphicBufferProducer;
+class IRegionSamplingListener;
 class Region;
 
 // ---------------------------------------------------------------------------
 
+struct SurfaceControlStats {
+    SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
+                        const sp<Fence>& prevReleaseFence)
+          : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
+
+    sp<SurfaceControl> surfaceControl;
+    nsecs_t acquireTime = -1;
+    sp<Fence> previousReleaseFence;
+};
+
+using TransactionCompletedCallbackTakesContext =
+        std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
+                           const sp<Fence>& /*presentFence*/,
+                           const std::vector<SurfaceControlStats>& /*stats*/)>;
+using TransactionCompletedCallback =
+        std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
+                           const std::vector<SurfaceControlStats>& /*stats*/)>;
+
+// ---------------------------------------------------------------------------
+
 class SurfaceComposerClient : public RefBase
 {
     friend class Composer;
 public:
                 SurfaceComposerClient();
                 SurfaceComposerClient(const sp<ISurfaceComposerClient>& client);
-                SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
     virtual     ~SurfaceComposerClient();
 
     // Always make sure we could initialize
@@ -69,7 +95,7 @@
 
     // callback when the composer is dies
     status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
-            void* cookie = NULL, uint32_t flags = 0);
+            void* cookie = nullptr, uint32_t flags = 0);
 
     // Get a list of supported configurations for a given display
     static status_t getDisplayConfigs(const sp<IBinder>& display,
@@ -79,9 +105,6 @@
     static status_t getDisplayInfo(const sp<IBinder>& display,
             DisplayInfo* info);
 
-    // Get the display viewport for the given display
-    static status_t getDisplayViewport(const sp<IBinder>& display, Rect* outViewport);
-
     // Get the index of the current active configuration (relative to the list
     // returned by getDisplayInfo)
     static int getActiveConfig(const sp<IBinder>& display);
@@ -90,10 +113,26 @@
     // returned by getDisplayInfo
     static status_t setActiveConfig(const sp<IBinder>& display, int id);
 
+    // Sets the allowed display configurations to be used.
+    // The allowedConfigs in a vector of indexes corresponding to the configurations
+    // returned from getDisplayConfigs().
+    static status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                             const std::vector<int32_t>& allowedConfigs);
+
+    // Returns the allowed display configurations currently set.
+    // The allowedConfigs in a vector of indexes corresponding to the configurations
+    // returned from getDisplayConfigs().
+    static status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+                                             std::vector<int32_t>* outAllowedConfigs);
+
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
             Vector<ui::ColorMode>* outColorModes);
 
+    // Get the coordinates of the display's native color primaries
+    static status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+            ui::DisplayPrimaries& outPrimaries);
+
     // Gets the active color mode for the given display
     static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
 
@@ -104,31 +143,107 @@
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
 
+    /* Returns the composition preference of the default data space and default pixel format,
+     * as well as the wide color gamut data space and wide color gamut pixel format.
+     * If the wide color gamut data space is V0_SRGB, then it implies that the platform
+     * has no wide color gamut support.
+     */
+    static status_t getCompositionPreference(ui::Dataspace* defaultDataspace,
+                                             ui::PixelFormat* defaultPixelFormat,
+                                             ui::Dataspace* wideColorGamutDataspace,
+                                             ui::PixelFormat* wideColorGamutPixelFormat);
+
+    /*
+     * Gets whether SurfaceFlinger can support protected content in GPU composition.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    static bool getProtectedContentSupport();
+
+    /**
+     * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
+     * to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
+     */
+    static void doDropReferenceTransaction(const sp<IBinder>& handle,
+            const sp<ISurfaceComposerClient>& client);
+
+    /**
+     * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
+     * in order with other transactions that use buffers.
+     */
+    static void doUncacheBufferTransaction(uint64_t cacheId);
+
+    // Queries whether a given display is wide color display.
+    static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
+
+    /*
+     * Returns whether brightness operations are supported on a display.
+     *
+     * displayToken
+     *      The token of the display.
+     *
+     * Returns whether brightness operations are supported on a display or not.
+     */
+    static bool getDisplayBrightnessSupport(const sp<IBinder>& displayToken);
+
+    /*
+     * Sets the brightness of a display.
+     *
+     * displayToken
+     *      The token of the display whose brightness is set.
+     * brightness
+     *      A number between 0.0 (minimum brightness) and 1.0 (maximum brightness), or -1.0f to
+     *      turn the backlight off.
+     *
+     * Returns NO_ERROR upon success. Otherwise,
+     *      NAME_NOT_FOUND    if the display handle is invalid, or
+     *      BAD_VALUE         if the brightness value is invalid, or
+     *      INVALID_OPERATION if brightness operaetions are not supported.
+     */
+    static status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness);
+
+    /*
+     * Sends a power hint to the composer. This function is asynchronous.
+     *
+     * hintId
+     *      hint id according to android::hardware::power::V1_0::PowerHint
+     *
+     * Returns NO_ERROR upon success.
+     */
+    static status_t notifyPowerHint(int32_t hintId);
+
     // ------------------------------------------------------------------------
     // surface creation / destruction
 
+    static sp<SurfaceComposerClient> getDefault();
+
     //! Create a surface
-    sp<SurfaceControl> createSurface(
-            const String8& name,// name of the surface
-            uint32_t w,         // width in pixel
-            uint32_t h,         // height in pixel
-            PixelFormat format, // pixel-format desired
-            uint32_t flags = 0, // usage flags
-            SurfaceControl* parent = nullptr, // parent
-            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            int32_t ownerUid = -1 // UID of the task
+    sp<SurfaceControl> createSurface(const String8& name,              // name of the surface
+                                     uint32_t w,                       // width in pixel
+                                     uint32_t h,                       // height in pixel
+                                     PixelFormat format,               // pixel-format desired
+                                     uint32_t flags = 0,               // usage flags
+                                     SurfaceControl* parent = nullptr, // parent
+                                     LayerMetadata metadata = LayerMetadata() // metadata
     );
 
-    status_t createSurfaceChecked(
-            const String8& name,// name of the surface
-            uint32_t w,         // width in pixel
-            uint32_t h,         // height in pixel
-            PixelFormat format, // pixel-format desired
-            sp<SurfaceControl>* outSurface,
-            uint32_t flags = 0, // usage flags
-            SurfaceControl* parent = nullptr, // parent
-            int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
-            int32_t ownerUid = -1 // UID of the task
+    status_t createSurfaceChecked(const String8& name, // name of the surface
+                                  uint32_t w,          // width in pixel
+                                  uint32_t h,          // height in pixel
+                                  PixelFormat format,  // pixel-format desired
+                                  sp<SurfaceControl>* outSurface,
+                                  uint32_t flags = 0,                      // usage flags
+                                  SurfaceControl* parent = nullptr,        // parent
+                                  LayerMetadata metadata = LayerMetadata() // metadata
+    );
+
+    //! Create a surface
+    sp<SurfaceControl> createWithSurfaceParent(const String8& name,       // name of the surface
+                                               uint32_t w,                // width in pixel
+                                               uint32_t h,                // height in pixel
+                                               PixelFormat format,        // pixel-format desired
+                                               uint32_t flags = 0,        // usage flags
+                                               Surface* parent = nullptr, // parent
+                                               LayerMetadata metadata = LayerMetadata() // metadata
     );
 
     //! Create a virtual display
@@ -137,9 +252,13 @@
     //! Destroy a virtual display
     static void destroyDisplay(const sp<IBinder>& display);
 
-    //! Get the token for the existing default displays.
-    //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
-    static sp<IBinder> getBuiltInDisplay(int32_t id);
+    //! Get stable IDs for connected physical displays
+    static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
+    static std::optional<PhysicalDisplayId> getInternalDisplayId();
+
+    //! Get token for a physical display given its stable ID
+    static sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId);
+    static sp<IBinder> getInternalDisplayToken();
 
     static status_t enableVSyncInjections(bool enable);
 
@@ -151,19 +270,56 @@
         }
     };
 
+    struct TCLHash {
+        std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
+            return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
+        }
+    };
+
+    struct CallbackInfo {
+        // All the callbacks that have been requested for a TransactionCompletedListener in the
+        // Transaction
+        std::unordered_set<CallbackId> callbackIds;
+        // All the SurfaceControls that have been modified in this TransactionCompletedListener's
+        // process that require a callback if there is one or more callbackIds set.
+        std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
+    };
+
     class Transaction {
         std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
         SortedVector<DisplayState > mDisplayStates;
+        std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+                mListenerCallbacks;
+
         uint32_t                    mForceSynchronous = 0;
         uint32_t                    mTransactionNestCount = 0;
         bool                        mAnimation = false;
         bool                        mEarlyWakeup = false;
 
+        // Indicates that the Transaction contains a buffer that should be cached
+        bool mContainsBuffer = false;
+
+        // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
+        // to be presented. When it is not possible to present at exactly that time, it will be
+        // presented after the time has passed.
+        //
+        // Desired present times that are more than 1 second in the future may be ignored.
+        // When a desired present time has already passed, the transaction will be presented as soon
+        // as possible.
+        //
+        // Transactions from the same process are presented in the same order that they are applied.
+        // The desired present time does not affect this ordering.
+        int64_t mDesiredPresentTime = -1;
+
+        InputWindowCommands mInputWindowCommands;
         int mStatus = NO_ERROR;
 
         layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
         DisplayState& getDisplayState(const sp<IBinder>& token);
 
+        void cacheBuffers();
+        void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
+
     public:
         Transaction() = default;
         virtual ~Transaction() = default;
@@ -203,22 +359,23 @@
                 float alpha);
         Transaction& setMatrix(const sp<SurfaceControl>& sc,
                 float dsdx, float dtdx, float dtdy, float dsdy);
-        Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
-        Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
         Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+        Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key,
+                                 std::vector<uint8_t> data);
         // 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
+        Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                  const sp<IBinder>& handle, uint64_t frameNumber);
+        // A variant of deferTransactionUntil_legacy 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);
+        Transaction& deferTransactionUntil_legacy(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);
@@ -231,6 +388,31 @@
 
         Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
 
+        // Sets the background color of a layer with the specified color, alpha, and dataspace
+        Transaction& setBackgroundColor(const sp<SurfaceControl>& sc, const half3& color,
+                                        float alpha, ui::Dataspace dataspace);
+
+        Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
+        Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
+                                                  bool transformToDisplayInverse);
+        Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
+        Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+        Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
+        Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
+        Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
+        Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
+        Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
+                                            const Region& surfaceDamageRegion);
+        Transaction& setApi(const sp<SurfaceControl>& sc, int32_t api);
+        Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
+                                       const sp<NativeHandle>& sidebandStream);
+        Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
+        Transaction& setColorSpaceAgnostic(const sp<SurfaceControl>& sc, const bool agnostic);
+
+        Transaction& addTransactionCompletedCallback(
+                TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
         // Detaches all child surfaces (and their children recursively)
         // from their SurfaceControl.
         // The child SurfaceControls will not throw exceptions or return errors,
@@ -254,7 +436,18 @@
         // freezing the total geometry of a surface until a resize is completed.
         Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
 
-        Transaction& destroySurface(const sp<SurfaceControl>& sc);
+#ifndef NO_INPUT
+        Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
+        Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
+        Transaction& syncInputWindows();
+#endif
+
+        // Set a color transform matrix on the given layer on the built-in display.
+        Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix,
+                                       const vec3& translation);
+
+        Transaction& setGeometry(const sp<SurfaceControl>& sc,
+                const Rect& source, const Rect& dst, int transform);
 
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
@@ -280,8 +473,6 @@
         void setEarlyWakeup();
     };
 
-    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();
@@ -297,13 +488,26 @@
 
     inline sp<ISurfaceComposerClient> getClient() { return mClient; }
 
+    static status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+                                                          ui::PixelFormat* outFormat,
+                                                          ui::Dataspace* outDataspace,
+                                                          uint8_t* outComponentMask);
+    static status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                     uint8_t componentMask, uint64_t maxFrames);
+
+    static status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                              uint64_t timestamp, DisplayedFrameStats* outStats);
+    static status_t addRegionSamplingListener(const Rect& samplingArea,
+                                              const sp<IBinder>& stopLayerHandle,
+                                              const sp<IRegionSamplingListener>& listener);
+    static status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener);
+
 private:
     virtual void onFirstRef();
 
     mutable     Mutex                       mLock;
                 status_t                    mStatus;
                 sp<ISurfaceComposerClient>  mClient;
-                wp<IGraphicBufferProducer>  mParent;
 };
 
 // ---------------------------------------------------------------------------
@@ -312,22 +516,74 @@
 public:
     // if cropping isn't required, callers may pass in a default Rect, e.g.:
     //   capture(display, producer, Rect(), reqWidth, ...);
-    static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
-                            uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
-                            bool useIdentityTransform, uint32_t rotation,
-                            bool captureSecureLayers, sp<GraphicBuffer>* outBuffer,
-                            bool& outCapturedSecureLayers);
-    static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth,
-                            uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ,
-                            bool useIdentityTransform, uint32_t rotation,
+    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                            uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                            uint32_t rotation, bool captureSecureLayers,
+                            sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers);
+    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                            uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                            uint32_t rotation, sp<GraphicBuffer>* outBuffer);
+    static status_t capture(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
                             sp<GraphicBuffer>* outBuffer);
-    static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale,
-                                  sp<GraphicBuffer>* outBuffer);
-    static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
-                                       float frameScale, sp<GraphicBuffer>* outBuffer);
+    static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+                                  const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                  float frameScale, sp<GraphicBuffer>* outBuffer);
+    static status_t captureChildLayers(
+            const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
+            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+            const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
+                    excludeHandles,
+            float frameScale, sp<GraphicBuffer>* outBuffer);
 };
 
 // ---------------------------------------------------------------------------
+
+class TransactionCompletedListener : public BnTransactionCompletedListener {
+    TransactionCompletedListener();
+
+    CallbackId getNextIdLocked() REQUIRES(mMutex);
+
+    std::mutex mMutex;
+
+    bool mListening GUARDED_BY(mMutex) = false;
+
+    CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
+
+    struct IBinderHash {
+        std::size_t operator()(const sp<IBinder>& iBinder) const {
+            return std::hash<IBinder*>{}(iBinder.get());
+        }
+    };
+
+    struct CallbackTranslation {
+        TransactionCompletedCallback callbackFunction;
+        std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+    };
+
+    std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+
+public:
+    static sp<TransactionCompletedListener> getInstance();
+    static sp<ITransactionCompletedListener> getIInstance();
+
+    void startListeningLocked() REQUIRES(mMutex);
+
+    CallbackId addCallbackFunction(
+            const TransactionCompletedCallback& callbackFunction,
+            const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
+                    surfaceControls);
+
+    void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
+                                      const std::unordered_set<CallbackId>& callbackIds);
+
+    // Overrides BnTransactionCompletedListener's onTransactionCompleted
+    void onTransactionCompleted(ListenerStats stats) override;
+};
+
+// ---------------------------------------------------------------------------
+
 }; // namespace android
 
 #endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 38de299..23bfc02 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -48,18 +48,22 @@
     void writeToParcel(Parcel* parcel);
 
     static bool isValid(const sp<SurfaceControl>& surface) {
-        return (surface != 0) && surface->isValid();
+        return (surface != nullptr) && surface->isValid();
     }
 
     bool isValid() {
-        return mHandle!=0 && mClient!=0;
+        return mHandle!=nullptr && mClient!=nullptr;
     }
 
     static bool isSameSurface(
             const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
 
-    // release surface data from java
-    void        clear();
+    // Release the handles assosciated with the SurfaceControl, without reparenting
+    // them off-screen. At the moment if this isn't executed before ~SurfaceControl
+    // is called then the destructor will reparent the layer off-screen for you.
+    void        release();
+    // Reparent off-screen and release. This is invoked by the destructor.
+    void destroy();
 
     // disconnect any api that's connected
     void        disconnect();
@@ -71,15 +75,18 @@
     sp<Surface> createSurface() const;
     sp<IBinder> getHandle() const;
 
+    sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
     sp<SurfaceComposerClient> getClient() const;
+    
+    explicit SurfaceControl(const sp<SurfaceControl>& other);
 
-    SurfaceControl(const sp<SurfaceComposerClient>& client,
-                   const sp<IBinder>& handle,
-                   const sp<IGraphicBufferProducer>& gbp,
-                   bool owned);
+    SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
+                   const sp<IGraphicBufferProducer>& gbp, bool owned);
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
@@ -92,7 +99,6 @@
 
     sp<Surface> generateSurfaceLocked() const;
     status_t validate() const;
-    void destroy();
 
     sp<SurfaceComposerClient>   mClient;
     sp<IBinder>                 mHandle;
diff --git a/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
index fa6c2d9..0f6fb45 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
@@ -50,7 +50,7 @@
 
 struct B2HProducerListener : public HProducerListener {
     sp<BProducerListener> mBase;
-    B2HProducerListener(sp<BProducerListener> const& base);
+    explicit B2HProducerListener(sp<BProducerListener> const& base);
     Return<void> onBufferReleased() override;
     Return<bool> needsReleaseNotify() override;
 };
diff --git a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h
new file mode 100644
index 0000000..627845c
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h
@@ -0,0 +1,765 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_CONVERSION_H_
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_CONVERSION_H_
+
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/Binder.h>
+#include <binder/Status.h>
+#include <ui/FenceTime.h>
+#include <cutils/native_handle.h>
+#include <gui/IGraphicBufferProducer.h>
+
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+
+namespace android {
+namespace conversion {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::status_t;
+
+using ::android::String8;
+
+using ::android::hardware::media::V1_0::Rect;
+using ::android::hardware::media::V1_0::Region;
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+using ::android::hardware::media::V1_0::AnwBuffer;
+using ::android::GraphicBuffer;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+        HGraphicBufferProducer;
+typedef ::android::IGraphicBufferProducer
+        BGraphicBufferProducer;
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+native_handle_t* native_handle_create_from_fd(int fd);
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+int native_handle_read_fd(native_handle_t const* nh, int index = 0);
+
+/**
+ * Conversion functions
+ * ====================
+ *
+ * There are two main directions of conversion:
+ * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the
+ *   input. The wrapper has type `TargetType`.
+ * - `toTargetType(...)`: Create a standalone object of type `TargetType` that
+ *   corresponds to the input. The lifetime of the output does not depend on the
+ *   lifetime of the input.
+ * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType`
+ *   that cannot be copied and/or moved efficiently, or when there are multiple
+ *   output arguments.
+ * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for
+ *   `TargetType` that cannot be copied and/or moved efficiently, or when there
+ *   are multiple output arguments.
+ *
+ * `wrapIn()` and `convertTo()` functions will take output arguments before
+ * input arguments. Some of these functions might return a value to indicate
+ * success or error.
+ *
+ * In converting or wrapping something as a Treble type that contains a
+ * `hidl_handle`, `native_handle_t*` will need to be created and returned as
+ * an additional output argument, hence only `wrapIn()` or `convertTo()` would
+ * be available. The caller must call `native_handle_delete()` to deallocate the
+ * returned native handle when it is no longer needed.
+ *
+ * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do
+ * not perform duplication of file descriptors, while `toTargetType()` and
+ * `convertTo()` do.
+ */
+
+/**
+ * \brief Convert `Return<void>` to `binder::Status`.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `binder::Status`.
+ */
+// convert: Return<void> -> ::android::binder::Status
+::android::binder::Status toBinderStatus(Return<void> const& t);
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+status_t toStatusT(Return<void> const& t);
+
+/**
+ * \brief Wrap `native_handle_t*` in `hidl_handle`.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \return The `hidl_handle` that points to \p nh.
+ */
+// wrap: native_handle_t* -> hidl_handle
+hidl_handle inHidlHandle(native_handle_t const* nh);
+
+/**
+ * \brief Convert `int32_t` to `Dataspace`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \result The corresponding `Dataspace`.
+ */
+// convert: int32_t -> Dataspace
+Dataspace toHardwareDataspace(int32_t l);
+
+/**
+ * \brief Convert `Dataspace` to `int32_t`.
+ *
+ * \param[in] t The source `Dataspace`.
+ * \result The corresponding `int32_t`.
+ */
+// convert: Dataspace -> int32_t
+int32_t toRawDataspace(Dataspace const& t);
+
+/**
+ * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that points to the buffer.
+ */
+// wrap: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size);
+
+/**
+ * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
+ */
+// convert: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size);
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+void wrapAs(AnwBuffer* t, GraphicBuffer const& l);
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+bool convertTo(GraphicBuffer* l, AnwBuffer const& t);
+
+/**
+ * Conversion functions for types outside media
+ * ============================================
+ *
+ * Some objects in libui and libgui that were made to go through binder calls do
+ * not expose ways to read or write their fields to the public. To pass an
+ * object of this kind through the HIDL boundary, translation functions need to
+ * work around the access restriction by using the publicly available
+ * `flatten()` and `unflatten()` functions.
+ *
+ * All `flatten()` and `unflatten()` overloads follow the same convention as
+ * follows:
+ *
+ *     status_t flatten(ObjectType const& object,
+ *                      [OtherType const& other, ...]
+ *                      void*& buffer, size_t& size,
+ *                      int*& fds, size_t& numFds)
+ *
+ *     status_t unflatten(ObjectType* object,
+ *                        [OtherType* other, ...,]
+ *                        void*& buffer, size_t& size,
+ *                        int*& fds, size_t& numFds)
+ *
+ * The number of `other` parameters varies depending on the `ObjectType`. For
+ * example, in the process of unflattening an object that contains
+ * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will
+ * be created.
+ *
+ * The last four parameters always work the same way in all overloads of
+ * `flatten()` and `unflatten()`:
+ * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled,
+ *   `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`,
+ *   `fds` is the pointer to the fd buffer to be filled, and `numFds` is the
+ *   size (in ints) of the fd buffer pointed to by `fds`.
+ * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read
+ *   from, `size` is the size (in bytes) of the non-fd buffer pointed to by
+ *   `buffer`, `fds` is the pointer to the fd buffer to be read from, and
+ *   `numFds` is the size (in ints) of the fd buffer pointed to by `fds`.
+ * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds`
+ *   will be advanced, while `size` and `numFds` will be decreased to reflect
+ *   how much storage/data of the two buffers (fd and non-fd) have been used.
+ * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and
+ *   `numFds` are invalid.
+ *
+ * The return value of a successful `flatten()` or `unflatten()` call will be
+ * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure.
+ *
+ * For each object type that supports flattening, there will be two accompanying
+ * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will
+ * return the size of the non-fd buffer that the object will need for
+ * flattening. `getFdCount()` will return the size of the fd buffer that the
+ * object will need for flattening.
+ *
+ * The set of these four functions, `getFlattenedSize()`, `getFdCount()`,
+ * `flatten()` and `unflatten()`, are similar to functions of the same name in
+ * the abstract class `Flattenable`. The only difference is that functions in
+ * this file are not member functions of the object type. For example, we write
+ *
+ *     flatten(x, buffer, size, fds, numFds)
+ *
+ * instead of
+ *
+ *     x.flatten(buffer, size, fds, numFds)
+ *
+ * because we cannot modify the type of `x`.
+ *
+ * There is one exception to the naming convention: `hidl_handle` that
+ * represents a fence. The four functions for this "Fence" type have the word
+ * "Fence" attched to their names because the object type, which is
+ * `hidl_handle`, does not carry the special meaning that the object itself can
+ * only contain zero or one file descriptor.
+ */
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+size_t getFenceFlattenedSize(hidl_handle const& fence);
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+size_t getFenceFdCount(hidl_handle const& fence);
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] t The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flattenFence(hidl_handle const& fence,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds);
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l);
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+bool convertTo(Fence* l, hidl_handle const& t);
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(HGraphicBufferProducer::FenceTimeSnapshot const& t);
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+size_t getFdCount(HGraphicBufferProducer::FenceTimeSnapshot const& t);
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`.
+ */
+status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds);
+
+/**
+ * \brief Unflatten `FenceTimeSnapshot`.
+ *
+ * \param[out] t The destination `FenceTimeSnapshot`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and the constructed snapshot contains a
+ * file descriptor, \p nh will be created to hold that file descriptor. In this
+ * case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
+ */
+status_t unflatten(
+        HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(HGraphicBufferProducer::FrameEventsDelta const& t);
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(HGraphicBufferProducer::FrameEventsDelta const& t);
+
+/**
+ * \brief Unflatten `FrameEventsDelta`.
+ *
+ * \param[out] t The destination `FrameEventsDelta`.
+ * \param[out] nh The underlying array of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be
+ * populated with `nullptr` or newly created handles. Each non-null slot in \p
+ * nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+        std::vector<native_handle_t*>* nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+//      FrameEventsDelta::flatten
+status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+        void*& buffer, size_t& size, int*& fds, size_t numFds);
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t);
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t);
+
+/**
+ * \brief Unflatten `FrameEventHistoryDelta`.
+ *
+ * \param[out] t The destination `FrameEventHistoryDelta`.
+ * \param[out] nh The underlying array of arrays of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or
+ * newly created handles. The second dimension of \p nh will be 4. Each non-null
+ * slot in \p nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(
+        HGraphicBufferProducer::FrameEventHistoryDelta* t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+status_t flatten(
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds);
+
+/**
+ * \brief Wrap `::android::FrameEventHistoryData` in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `::android::FrameEventHistoryDelta`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        ::android::FrameEventHistoryDelta const& l);
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+bool convertTo(
+        ::android::FrameEventHistoryDelta* l,
+        HGraphicBufferProducer::FrameEventHistoryDelta const& t);
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Return the size of the buffer required to flatten `Region`.
+ *
+ * \param[in] t The input `Region`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(Region const& t);
+
+/**
+ * \brief Unflatten `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t unflatten(Region* t, void const*& buffer, size_t& size);
+
+/**
+ * \brief Flatten `Region`.
+ *
+ * \param[in] t The source `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flatten(Region const& t, void*& buffer, size_t& size);
+
+/**
+ * \brief Convert `::android::Region` to `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in] l The source `::android::Region`.
+ */
+// convert: ::android::Region -> Region
+bool convertTo(Region* t, ::android::Region const& l);
+
+/**
+ * \brief Convert `Region` to `::android::Region`.
+ *
+ * \param[out] l The destination `::android::Region`.
+ * \param[in] t The source `Region`.
+ */
+// convert: Region -> ::android::Region
+bool convertTo(::android::Region* l, Region const& t);
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+//      BGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t);
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+        HGraphicBufferProducer::QueueBufferInput const& t);
+/**
+ * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence`. */
+status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+        native_handle_t** nh,
+        void*& buffer, size_t& size, int*& fds, size_t& numFds);
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflatten(
+        HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+        void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+bool wrapAs(
+        HGraphicBufferProducer::QueueBufferInput* t,
+        native_handle_t** nh,
+        BGraphicBufferProducer::QueueBufferInput const& l);
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
+ * `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If `t.fence` has a valid file descriptor, it will be duplicated.
+ */
+bool convertTo(
+        BGraphicBufferProducer::QueueBufferInput* l,
+        HGraphicBufferProducer::QueueBufferInput const& t);
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+//      BGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+// wrap: BGraphicBufferProducer::QueueBufferOutput ->
+// HGraphicBufferProducer::QueueBufferOutput
+bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+        std::vector<std::vector<native_handle_t*> >* nh,
+        BGraphicBufferProducer::QueueBufferOutput const& l);
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// BGraphicBufferProducer::QueueBufferOutput
+bool convertTo(
+        BGraphicBufferProducer::QueueBufferOutput* l,
+        HGraphicBufferProducer::QueueBufferOutput const& t);
+
+/**
+ * \brief Convert `BGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+        BGraphicBufferProducer::DisconnectMode l);
+
+/**
+ * \brief Convert `HGraphicBufferProducer::DisconnectMode` to
+ * `BGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
+ */
+BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+        HGraphicBufferProducer::DisconnectMode t);
+
+}  // namespace conversion
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_CONVERSION_H_
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index 74850b4..c4d0245 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -57,9 +57,8 @@
 
 struct H2BGraphicBufferProducer : public ::android::H2BConverter<
         HGraphicBufferProducer,
-        BGraphicBufferProducer,
         BnGraphicBufferProducer> {
-    H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+    explicit H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
 
     status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
     status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
new file mode 100644
index 0000000..211fdd5
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V1_0::
+        IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+class H2BProducerListener
+      : public H2BConverter<HProducerListener, BnProducerListener> {
+public:
+    H2BProducerListener(sp<HProducerListener> const& base);
+    virtual void onBufferReleased() override;
+    virtual bool needsReleaseNotify() override;
+};
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
new file mode 100644
index 0000000..029dcc0
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WGRAPHICBUFFERPRODUCER_H_
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WGRAPHICBUFFERPRODUCER_H_
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/Binder.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <gui/bufferqueue/1.0/Conversion.h>
+#include <gui/bufferqueue/1.0/WProducerListener.h>
+#include <system/window.h>
+
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
+namespace android {
+
+using ::android::hardware::media::V1_0::AnwBuffer;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::
+        IGraphicBufferProducer HGraphicBufferProducer;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::
+        IProducerListener HProducerListener;
+
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+typedef ::android::IProducerListener BProducerListener;
+using ::android::BnGraphicBufferProducer;
+
+#ifndef LOG
+struct LOG_dummy {
+    template <typename T>
+    LOG_dummy& operator<< (const T&) { return *this; }
+};
+
+#define LOG(x)  LOG_dummy()
+#endif
+
+// Instantiate only if HGraphicBufferProducer is base of BASE.
+template <typename BASE,
+          typename = typename std::enable_if<std::is_base_of<HGraphicBufferProducer, BASE>::value>::type>
+struct TWGraphicBufferProducer : public BASE {
+    TWGraphicBufferProducer(sp<BGraphicBufferProducer> const& base) : mBase(base) {}
+    Return<void> requestBuffer(int32_t slot, HGraphicBufferProducer::requestBuffer_cb _hidl_cb) override {
+        sp<GraphicBuffer> buf;
+        status_t status = mBase->requestBuffer(slot, &buf);
+        AnwBuffer anwBuffer{};
+        if (buf != nullptr) {
+            ::android::conversion::wrapAs(&anwBuffer, *buf);
+        }
+        _hidl_cb(static_cast<int32_t>(status), anwBuffer);
+        return Void();
+    }
+
+    Return<int32_t> setMaxDequeuedBufferCount(int32_t maxDequeuedBuffers) override {
+        return static_cast<int32_t>(mBase->setMaxDequeuedBufferCount(
+                static_cast<int>(maxDequeuedBuffers)));
+    }
+
+    Return<int32_t> setAsyncMode(bool async) override {
+        return static_cast<int32_t>(mBase->setAsyncMode(async));
+    }
+
+    Return<void> dequeueBuffer(
+            uint32_t width, uint32_t height,
+            ::android::hardware::graphics::common::V1_0::PixelFormat format, uint32_t usage,
+            bool getFrameTimestamps, HGraphicBufferProducer::dequeueBuffer_cb _hidl_cb) override {
+        int slot{};
+        sp<Fence> fence;
+        ::android::FrameEventHistoryDelta outTimestamps;
+        status_t status = mBase->dequeueBuffer(
+            &slot, &fence, width, height,
+            static_cast<::android::PixelFormat>(format), usage, nullptr,
+            getFrameTimestamps ? &outTimestamps : nullptr);
+        hidl_handle tFence{};
+        HGraphicBufferProducer::FrameEventHistoryDelta tOutTimestamps{};
+
+        native_handle_t* nh = nullptr;
+        if ((fence == nullptr) || !::android::conversion::wrapAs(&tFence, &nh, *fence)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - "
+                    "Invalid output fence";
+            _hidl_cb(static_cast<int32_t>(status),
+                     static_cast<int32_t>(slot),
+                     tFence,
+                     tOutTimestamps);
+            return Void();
+        }
+        std::vector<std::vector<native_handle_t*> > nhAA;
+        if (getFrameTimestamps && !::android::conversion::wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - "
+                    "Invalid output timestamps";
+            _hidl_cb(static_cast<int32_t>(status),
+                     static_cast<int32_t>(slot),
+                     tFence,
+                     tOutTimestamps);
+            native_handle_delete(nh);
+            return Void();
+        }
+
+        _hidl_cb(static_cast<int32_t>(status),
+                static_cast<int32_t>(slot),
+                tFence,
+                tOutTimestamps);
+        native_handle_delete(nh);
+        if (getFrameTimestamps) {
+            for (auto& nhA : nhAA) {
+                for (auto& handle : nhA) {
+                    native_handle_delete(handle);
+                }
+            }
+        }
+        return Void();
+    }
+
+    Return<int32_t> detachBuffer(int32_t slot) override {
+        return static_cast<int32_t>(mBase->detachBuffer(slot));
+    }
+
+    Return<void> detachNextBuffer(HGraphicBufferProducer::detachNextBuffer_cb _hidl_cb) override {
+        sp<GraphicBuffer> outBuffer;
+        sp<Fence> outFence;
+        status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
+        AnwBuffer tBuffer{};
+        hidl_handle tFence{};
+
+        if (outBuffer == nullptr) {
+            LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
+                    "Invalid output buffer";
+            _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
+            return Void();
+        }
+        ::android::conversion::wrapAs(&tBuffer, *outBuffer);
+        native_handle_t* nh = nullptr;
+        if ((outFence != nullptr) && !::android::conversion::wrapAs(&tFence, &nh, *outFence)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
+                    "Invalid output fence";
+            _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
+            return Void();
+        }
+
+        _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
+        native_handle_delete(nh);
+        return Void();
+    }
+
+    Return<void> attachBuffer(const AnwBuffer& buffer, HGraphicBufferProducer::attachBuffer_cb _hidl_cb) override {
+        int outSlot;
+        sp<GraphicBuffer> lBuffer = new GraphicBuffer();
+        if (!::android::conversion::convertTo(lBuffer.get(), buffer)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::attachBuffer - "
+                    "Invalid input native window buffer";
+            _hidl_cb(static_cast<int32_t>(BAD_VALUE), -1);
+            return Void();
+        }
+        status_t status = mBase->attachBuffer(&outSlot, lBuffer);
+
+        _hidl_cb(static_cast<int32_t>(status), static_cast<int32_t>(outSlot));
+        return Void();
+    }
+
+    Return<void> queueBuffer(
+            int32_t slot, const HGraphicBufferProducer::QueueBufferInput& input,
+            HGraphicBufferProducer::queueBuffer_cb _hidl_cb) override {
+        HGraphicBufferProducer::QueueBufferOutput tOutput{};
+        BGraphicBufferProducer::QueueBufferInput lInput(
+                0, false, HAL_DATASPACE_UNKNOWN,
+                ::android::Rect(0, 0, 1, 1),
+                NATIVE_WINDOW_SCALING_MODE_FREEZE,
+                0, ::android::Fence::NO_FENCE);
+        if (!::android::conversion::convertTo(&lInput, input)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - "
+                    "Invalid input";
+            _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput);
+            return Void();
+        }
+        BGraphicBufferProducer::QueueBufferOutput lOutput;
+        status_t status = mBase->queueBuffer(
+                static_cast<int>(slot), lInput, &lOutput);
+
+        std::vector<std::vector<native_handle_t*> > nhAA;
+        if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - "
+                    "Invalid output";
+            _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput);
+            return Void();
+        }
+
+        _hidl_cb(static_cast<int32_t>(status), tOutput);
+        for (auto& nhA : nhAA) {
+            for (auto& nh : nhA) {
+                native_handle_delete(nh);
+            }
+        }
+        return Void();
+    }
+
+    Return<int32_t> cancelBuffer(int32_t slot, const hidl_handle& fence) override {
+        sp<Fence> lFence = new Fence();
+        if (!::android::conversion::convertTo(lFence.get(), fence)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::cancelBuffer - "
+                    "Invalid input fence";
+            return static_cast<int32_t>(BAD_VALUE);
+        }
+        return static_cast<int32_t>(mBase->cancelBuffer(static_cast<int>(slot), lFence));
+    }
+
+    Return<void> query(int32_t what, HGraphicBufferProducer::query_cb _hidl_cb) override {
+        int lValue;
+        int lReturn = mBase->query(static_cast<int>(what), &lValue);
+        _hidl_cb(static_cast<int32_t>(lReturn), static_cast<int32_t>(lValue));
+        return Void();
+    }
+
+    Return<void> connect(const sp<HProducerListener>& listener,
+            int32_t api, bool producerControlledByApp,
+            HGraphicBufferProducer::connect_cb _hidl_cb) override {
+        sp<BProducerListener> lListener = listener == nullptr ?
+                nullptr : new LWProducerListener(listener);
+        BGraphicBufferProducer::QueueBufferOutput lOutput;
+        status_t status = mBase->connect(lListener,
+                static_cast<int>(api),
+                producerControlledByApp,
+                &lOutput);
+
+        HGraphicBufferProducer::QueueBufferOutput tOutput{};
+        std::vector<std::vector<native_handle_t*> > nhAA;
+        if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::connect - "
+                    "Invalid output";
+            _hidl_cb(static_cast<int32_t>(status), tOutput);
+            return Void();
+        }
+
+        _hidl_cb(static_cast<int32_t>(status), tOutput);
+        for (auto& nhA : nhAA) {
+            for (auto& nh : nhA) {
+                native_handle_delete(nh);
+            }
+        }
+        return Void();
+    }
+
+    Return<int32_t> disconnect(
+            int32_t api,
+            HGraphicBufferProducer::DisconnectMode mode) override {
+        return static_cast<int32_t>(mBase->disconnect(
+                static_cast<int>(api),
+                ::android::conversion::toGuiDisconnectMode(mode)));
+    }
+
+    Return<int32_t> setSidebandStream(const hidl_handle& stream) override {
+        return static_cast<int32_t>(mBase->setSidebandStream(NativeHandle::create(
+                stream ? native_handle_clone(stream) : NULL, true)));
+    }
+
+    Return<void> allocateBuffers(
+            uint32_t width, uint32_t height,
+            ::android::hardware::graphics::common::V1_0::PixelFormat format,
+            uint32_t usage) override {
+        mBase->allocateBuffers(
+                width, height,
+                static_cast<::android::PixelFormat>(format),
+                usage);
+        return Void();
+    }
+
+    Return<int32_t> allowAllocation(bool allow) override {
+        return static_cast<int32_t>(mBase->allowAllocation(allow));
+    }
+
+    Return<int32_t> setGenerationNumber(uint32_t generationNumber) override {
+        return static_cast<int32_t>(mBase->setGenerationNumber(generationNumber));
+    }
+
+    Return<void> getConsumerName(HGraphicBufferProducer::getConsumerName_cb _hidl_cb) override {
+        _hidl_cb(mBase->getConsumerName().string());
+        return Void();
+    }
+
+    Return<int32_t> setSharedBufferMode(bool sharedBufferMode) override {
+        return static_cast<int32_t>(mBase->setSharedBufferMode(sharedBufferMode));
+    }
+
+    Return<int32_t> setAutoRefresh(bool autoRefresh) override {
+        return static_cast<int32_t>(mBase->setAutoRefresh(autoRefresh));
+    }
+
+    Return<int32_t> setDequeueTimeout(int64_t timeoutNs) override {
+        return static_cast<int32_t>(mBase->setDequeueTimeout(timeoutNs));
+    }
+
+    Return<void> getLastQueuedBuffer(HGraphicBufferProducer::getLastQueuedBuffer_cb _hidl_cb) override {
+        sp<GraphicBuffer> lOutBuffer = new GraphicBuffer();
+        sp<Fence> lOutFence = new Fence();
+        float lOutTransformMatrix[16];
+        status_t status = mBase->getLastQueuedBuffer(
+                &lOutBuffer, &lOutFence, lOutTransformMatrix);
+
+        AnwBuffer tOutBuffer{};
+        if (lOutBuffer != nullptr) {
+            ::android::conversion::wrapAs(&tOutBuffer, *lOutBuffer);
+        }
+        hidl_handle tOutFence{};
+        native_handle_t* nh = nullptr;
+        if ((lOutFence == nullptr) || !::android::conversion::wrapAs(&tOutFence, &nh, *lOutFence)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::getLastQueuedBuffer - "
+                    "Invalid output fence";
+            _hidl_cb(static_cast<int32_t>(status),
+                    tOutBuffer,
+                    tOutFence,
+                    hidl_array<float, 16>());
+            return Void();
+        }
+        hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
+
+        _hidl_cb(static_cast<int32_t>(status), tOutBuffer, tOutFence, tOutTransformMatrix);
+        native_handle_delete(nh);
+        return Void();
+    }
+
+    Return<void> getFrameTimestamps(HGraphicBufferProducer::getFrameTimestamps_cb _hidl_cb) override {
+        ::android::FrameEventHistoryDelta lDelta;
+        mBase->getFrameTimestamps(&lDelta);
+
+        HGraphicBufferProducer::FrameEventHistoryDelta tDelta{};
+        std::vector<std::vector<native_handle_t*> > nhAA;
+        if (!::android::conversion::wrapAs(&tDelta, &nhAA, lDelta)) {
+            LOG(ERROR) << "TWGraphicBufferProducer::getFrameTimestamps - "
+                    "Invalid output frame timestamps";
+            _hidl_cb(tDelta);
+            return Void();
+        }
+
+        _hidl_cb(tDelta);
+        for (auto& nhA : nhAA) {
+            for (auto& nh : nhA) {
+                native_handle_delete(nh);
+            }
+        }
+        return Void();
+    }
+
+    Return<void> getUniqueId(HGraphicBufferProducer::getUniqueId_cb _hidl_cb) override {
+        uint64_t outId{};
+        status_t status = mBase->getUniqueId(&outId);
+        _hidl_cb(static_cast<int32_t>(status), outId);
+        return Void();
+    }
+
+private:
+    sp<BGraphicBufferProducer> mBase;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WGRAPHICBUFFERPRODUCER_H_
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h
new file mode 100644
index 0000000..51dff5b
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WPRODUCERLISTENER_H_
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WPRODUCERLISTENER_H_
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+
+namespace android {
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener
+        HProducerListener;
+typedef ::android::IProducerListener
+        BProducerListener;
+using ::android::BnProducerListener;
+
+struct TWProducerListener : public HProducerListener {
+    sp<BProducerListener> mBase;
+    TWProducerListener(sp<BProducerListener> const& base);
+    Return<void> onBufferReleased() override;
+    Return<bool> needsReleaseNotify() override;
+};
+
+class LWProducerListener : public BnProducerListener {
+public:
+    sp<HProducerListener> mBase;
+    LWProducerListener(sp<HProducerListener> const& base);
+    void onBufferReleased() override;
+    bool needsReleaseNotify() override;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_WPRODUCERLISTENER_H_
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
new file mode 100644
index 0000000..1c58167
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using HGraphicBufferProducer =
+        ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer;
+using BGraphicBufferProducer =
+        ::android::
+        IGraphicBufferProducer;
+using HProducerListener =
+        ::android::hardware::graphics::bufferqueue::V2_0::
+        IProducerListener;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+using ::android::hardware::graphics::common::V1_2::HardwareBuffer;
+
+class B2HGraphicBufferProducer : public HGraphicBufferProducer {
+public:
+    B2HGraphicBufferProducer(sp<BGraphicBufferProducer> const& base);
+
+    virtual Return<HStatus> setMaxDequeuedBufferCount(
+            int32_t maxDequeuedBuffers) override;
+
+    virtual Return<void> requestBuffer(
+            int32_t slot,
+            requestBuffer_cb _hidl_cb) override;
+
+    virtual Return<HStatus> setAsyncMode(bool async) override;
+
+    virtual Return<void> dequeueBuffer(
+            DequeueBufferInput const& input,
+            dequeueBuffer_cb _hidl_cb) override;
+
+    virtual Return<HStatus> detachBuffer(int32_t slot) override;
+
+    virtual Return<void> detachNextBuffer(
+            detachNextBuffer_cb _hidl_cb) override;
+
+    virtual Return<void> attachBuffer(
+            HardwareBuffer const& buffer,
+            uint32_t generationNumber,
+            attachBuffer_cb _hidl_cb) override;
+
+    virtual Return<void> queueBuffer(
+            int32_t slot,
+            QueueBufferInput const& input,
+            queueBuffer_cb _hidl_cb) override;
+
+    virtual Return<HStatus> cancelBuffer(
+            int32_t slot,
+            hidl_handle const& fence) override;
+
+    virtual Return<void> query(int32_t what, query_cb _hidl_cb) override;
+
+    virtual Return<void> connect(
+            sp<HProducerListener> const& listener,
+            HConnectionType api,
+            bool producerControlledByApp,
+            connect_cb _hidl_cb) override;
+
+    virtual Return<HStatus> disconnect(HConnectionType api) override;
+
+    virtual Return<HStatus> allocateBuffers(
+            uint32_t width, uint32_t height,
+            uint32_t format, uint64_t usage) override;
+
+    virtual Return<HStatus> allowAllocation(bool allow) override;
+
+    virtual Return<HStatus> setGenerationNumber(uint32_t generationNumber) override;
+
+    virtual Return<HStatus> setDequeueTimeout(int64_t timeoutNs) override;
+
+    virtual Return<uint64_t> getUniqueId() override;
+
+    virtual Return<void> getConsumerName(getConsumerName_cb _hidl_cb) override;
+
+protected:
+    sp<BGraphicBufferProducer> mBase;
+};
+
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h
new file mode 100644
index 0000000..b48a473
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+#include <hidl/Status.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::
+        IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+struct B2HProducerListener : public HProducerListener {
+    explicit B2HProducerListener(sp<BProducerListener> const& base);
+    Return<void> onBuffersReleased(uint32_t count) override;
+protected:
+    sp<BProducerListener> mBase;
+    bool mNeedsReleaseNotify;
+};
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h
new file mode 100644
index 0000000..7dd1617
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+#include <ui/Fence.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::BnGraphicBufferProducer;
+using ::android::IProducerListener;
+using Fence = ::android::Fence;
+
+using HGraphicBufferProducer =
+        ::android::hardware::graphics::bufferqueue::V2_0::
+        IGraphicBufferProducer;
+using HProducerListener =
+        ::android::hardware::graphics::bufferqueue::V2_0::
+        IProducerListener;
+using BGraphicBufferProducer =
+        ::android::IGraphicBufferProducer;
+
+struct H2BGraphicBufferProducer
+      : public ::android::H2BConverter<HGraphicBufferProducer,
+                                       BnGraphicBufferProducer> {
+    explicit H2BGraphicBufferProducer(
+            sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
+    virtual status_t setAsyncMode(bool async) override;
+    virtual status_t dequeueBuffer(
+            int* slot, sp<Fence>* fence,
+            uint32_t width, uint32_t height,
+            PixelFormat format, uint64_t usage,
+            uint64_t* outBufferAge,
+            FrameEventHistoryDelta* outTimestamps) override;
+    virtual status_t detachBuffer(int slot) override;
+    virtual status_t detachNextBuffer(
+            sp<GraphicBuffer>* outBuffer,
+            sp<Fence>* outFence) override;
+    virtual status_t attachBuffer(
+            int* outSlot,
+            sp<GraphicBuffer> const& buffer) override;
+    virtual status_t queueBuffer(
+            int slot,
+            QueueBufferInput const& input,
+            QueueBufferOutput* output) override;
+    virtual status_t cancelBuffer(int slot, sp<Fence> const& fence) override;
+    virtual int query(int what, int* value) override;
+    virtual status_t connect(
+            sp<IProducerListener> const& listener,
+            int api,
+            bool producerControlledByApp,
+            QueueBufferOutput* output) override;
+    virtual status_t disconnect(
+            int api,
+            DisconnectMode mode = DisconnectMode::Api) override;
+    virtual status_t setSidebandStream(sp<NativeHandle> const& stream) override;
+    virtual void allocateBuffers(
+            uint32_t width, uint32_t height,
+            PixelFormat format, uint64_t usage) override;
+    virtual status_t allowAllocation(bool allow) override;
+    virtual status_t setGenerationNumber(uint32_t generationNumber) override;
+    virtual String8 getConsumerName() const override;
+    virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
+    virtual status_t setAutoRefresh(bool autoRefresh) override;
+    virtual status_t setDequeueTimeout(nsecs_t timeout) override;
+    virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+          sp<Fence>* outFence, float outTransformMatrix[16]) override;
+    virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
+    virtual status_t getUniqueId(uint64_t* outId) const override;
+    virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+};
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
new file mode 100644
index 0000000..898920b
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::
+        IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+class H2BProducerListener
+      : public H2BConverter<HProducerListener, BnProducerListener> {
+public:
+    H2BProducerListener(sp<HProducerListener> const& base);
+    virtual void onBufferReleased() override;
+    virtual bool needsReleaseNotify() override;
+};
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/types.h b/libs/gui/include/gui/bufferqueue/2.0/types.h
new file mode 100644
index 0000000..62176ce
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/types.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <hidl/HidlSupport.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::
+        Status;
+
+// A status_t value may have flags encoded. These flags are decoded into boolean
+// values if their corresponding output pointers are not null.
+bool b2h(status_t from, HStatus* to,
+         bool* bufferNeedsReallocation = nullptr,
+         bool* releaseAllBuffers = nullptr);
+// Simple 1-to-1 mapping. If BUFFER_NEEDS_REALLOCATION or RELEASE_ALL_BUFFERS
+// needs to be added, it must be done manually afterwards.
+bool h2b(HStatus from, status_t* to);
+
+// Fence
+// =====
+
+using BFence = ::android::Fence;
+// This class manages the lifetime of a copied handle. Its destructor calls
+// native_handle_delete() but not native_handle_close().
+struct HFenceWrapper {
+    HFenceWrapper() = default;
+    // Sets mHandle to a new value.
+    HFenceWrapper(native_handle_t* h);
+    // Deletes mHandle without closing.
+    ~HFenceWrapper();
+    // Deletes mHandle without closing, then sets mHandle to a new value.
+    HFenceWrapper& set(native_handle_t* h);
+    HFenceWrapper& operator=(native_handle_t* h);
+    // Returns a non-owning hidl_handle pointing to mHandle.
+    hidl_handle getHandle() const;
+    operator hidl_handle() const;
+protected:
+    native_handle_t* mHandle{nullptr};
+};
+
+// Does not clone the fd---only copy the fd. The returned HFenceWrapper should
+// not outlive the input Fence object.
+bool b2h(sp<BFence> const& from, HFenceWrapper* to);
+// Clones the fd and puts it in a new Fence object.
+bool h2b(native_handle_t const* from, sp<BFence>* to);
+
+// ConnectionType
+// ==============
+
+using HConnectionType = ::android::hardware::graphics::bufferqueue::V2_0::
+        ConnectionType;
+
+bool b2h(int from, HConnectionType* to);
+bool h2b(HConnectionType from, int* to);
+
+// Rect
+// ====
+
+using BRect = ::android::Rect;
+using HRect = ::android::hardware::graphics::common::V1_2::Rect;
+
+bool b2h(BRect const& from, HRect* to);
+bool h2b(HRect const& from, BRect* to);
+
+// Region
+// ======
+
+using BRegion = ::android::Region;
+using HRegion = ::android::hardware::hidl_vec<HRect>;
+
+bool b2h(BRegion const& from, HRegion* to);
+bool h2b(HRegion const& from, BRegion* to);
+
+// GraphicBuffer
+// =============
+
+using HardwareBuffer = ::android::hardware::graphics::common::V1_2::
+        HardwareBuffer;
+using HardwareBufferDescription = ::android::hardware::graphics::common::V1_2::
+        HardwareBufferDescription;
+
+// Does not clone the handle. The returned HardwareBuffer should not outlive the
+// input GraphicBuffer. Note that HardwareBuffer does not carry the generation
+// number, so this function needs another output argument.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+         uint32_t* toGenerationNumber = nullptr);
+// Clones the handle and creates a new GraphicBuffer from the cloned handle.
+// Note that the generation number of the GraphicBuffer has to be set manually
+// afterwards because HardwareBuffer does not have such information.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to);
+
+}  // namespace utils
+}  // namespace V2_0
+}  // namespace bufferqueue
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+
diff --git a/libs/gui/include/private/gui/BufferQueueThreadState.h b/libs/gui/include/private/gui/BufferQueueThreadState.h
new file mode 100644
index 0000000..67dcf62
--- /dev/null
+++ b/libs/gui/include/private/gui/BufferQueueThreadState.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+// TODO: Replace this with b/127962003
+class BufferQueueThreadState {
+public:
+    static pid_t getCallingPid();
+    static uid_t getCallingUid();
+};
+
+} // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 01e90e0..ab6dcaa 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -16,11 +16,14 @@
         "BufferItemConsumer_test.cpp",
         "BufferQueue_test.cpp",
         "CpuConsumer_test.cpp",
+        "EndToEndNativeInputTest.cpp",
+        "DisplayedContentSampling_test.cpp",
         "FillBuffer.cpp",
         "GLTest.cpp",
         "IGraphicBufferProducer_test.cpp",
         "Malicious.cpp",
         "MultiTextureConsumer_test.cpp",
+        "RegionSampling_test.cpp",
         "StreamSplitter_test.cpp",
         "SurfaceTextureClient_test.cpp",
         "SurfaceTextureFBO_test.cpp",
@@ -35,6 +38,7 @@
     shared_libs: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
+        "libbase",
         "liblog",
         "libEGL",
         "libGLESv1_CM",
@@ -44,15 +48,19 @@
         "libgui",
         "libhidlbase",
         "libhidltransport",
+        "libinput",
         "libui",
         "libutils",
         "libnativewindow"
     ],
 }
 
-// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// This test has a main method, and requires a separate binary to be built.
+// To add move tests like this, just add additional cc_test statements,
+// as opposed to adding more source files to this one.
 cc_test {
-    name: "libgui_separate_binary_test",
+    name: "SurfaceParcelable_test",
     test_suites: ["device-tests"],
 
     clang: true,
@@ -61,7 +69,6 @@
         "-Werror",
     ],
 
-    test_per_src: true,
     srcs: [
         "SurfaceParcelable_test.cpp",
     ],
@@ -81,3 +88,26 @@
         "libdvr_headers",
     ],
 }
+
+cc_test {
+    name: "SamplingDemo",
+
+    clang: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: [
+        "SamplingDemo.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libgui",
+        "liblog",
+        "libui",
+        "libutils",
+    ]
+}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 9a20859..119e888 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -61,7 +61,7 @@
     }
 
     void GetMinUndequeuedBufferCount(int* bufferCount) {
-        ASSERT_TRUE(bufferCount != NULL);
+        ASSERT_TRUE(bufferCount != nullptr);
         ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
                     bufferCount));
         ASSERT_GE(*bufferCount, 0);
@@ -82,7 +82,7 @@
         sp<Fence> fence;
 
         input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop,
-                &scalingMode, &transform, &fence, NULL);
+                &scalingMode, &transform, &fence, nullptr);
         ASSERT_EQ(timestamp, item.mTimestamp);
         ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp);
         ASSERT_EQ(dataSpace, item.mDataSpace);
@@ -128,17 +128,17 @@
     sp<IBinder> binderProducer =
         serviceManager->getService(PRODUCER_NAME);
     mProducer = interface_cast<IGraphicBufferProducer>(binderProducer);
-    EXPECT_TRUE(mProducer != NULL);
+    EXPECT_TRUE(mProducer != nullptr);
     sp<IBinder> binderConsumer =
         serviceManager->getService(CONSUMER_NAME);
     mConsumer = interface_cast<IGraphicBufferConsumer>(binderConsumer);
-    EXPECT_TRUE(mConsumer != NULL);
+    EXPECT_TRUE(mConsumer != nullptr);
 
     sp<DummyConsumer> dc(new DummyConsumer);
     ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
     ASSERT_EQ(OK,
-            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+            mProducer->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot;
     sp<Fence> fence;
@@ -353,8 +353,8 @@
     ASSERT_EQ(OK, buffer->unlock());
 
     int newSlot;
-    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(NULL, safeToClobberBuffer));
-    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL));
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(nullptr, safeToClobberBuffer));
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, nullptr));
 
     ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer));
     IGraphicBufferProducer::QueueBufferInput input(0, false,
@@ -412,8 +412,8 @@
 
     int newSlot;
     sp<GraphicBuffer> safeToClobberBuffer;
-    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(NULL, safeToClobberBuffer));
-    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, NULL));
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(nullptr, safeToClobberBuffer));
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, nullptr));
     ASSERT_EQ(OK, mConsumer->attachBuffer(&newSlot, item.mGraphicBuffer));
 
     ASSERT_EQ(OK, mConsumer->releaseBuffer(newSlot, 0, EGL_NO_DISPLAY,
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 36be7d9..00e32d9 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -484,12 +484,12 @@
     err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
     ASSERT_NO_ERROR(err, "dequeueBuffer error: ");
 
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     *stride = buf->getStride();
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
 
     ALOGVV("Lock buffer from %p for write", anw.get());
     err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
@@ -554,7 +554,7 @@
     err = mCC->lockNextBuffer(&b);
     ASSERT_NO_ERROR(err, "getNextBuffer error: ");
 
-    ASSERT_TRUE(b.data != NULL);
+    ASSERT_TRUE(b.data != nullptr);
     EXPECT_EQ(params.width,  b.width);
     EXPECT_EQ(params.height, b.height);
     EXPECT_EQ(params.format, b.format);
@@ -595,7 +595,7 @@
         err = mCC->lockNextBuffer(&b);
         ASSERT_NO_ERROR(err, "getNextBuffer error: ");
 
-        ASSERT_TRUE(b.data != NULL);
+        ASSERT_TRUE(b.data != nullptr);
         EXPECT_EQ(params.width,  b.width);
         EXPECT_EQ(params.height, b.height);
         EXPECT_EQ(params.format, b.format);
@@ -637,7 +637,7 @@
         err = mCC->lockNextBuffer(&b[i]);
         ASSERT_NO_ERROR(err, "getNextBuffer error: ");
 
-        ASSERT_TRUE(b[i].data != NULL);
+        ASSERT_TRUE(b[i].data != nullptr);
         EXPECT_EQ(params.width,  b[i].width);
         EXPECT_EQ(params.height, b[i].height);
         EXPECT_EQ(params.format, b[i].format);
@@ -660,7 +660,7 @@
     err = mCC->lockNextBuffer(&bTooMuch);
     ASSERT_NO_ERROR(err, "Did not allow new lock after unlock");
 
-    ASSERT_TRUE(bTooMuch.data != NULL);
+    ASSERT_TRUE(bTooMuch.data != nullptr);
     EXPECT_EQ(params.width,  bTooMuch.width);
     EXPECT_EQ(params.height, bTooMuch.height);
     EXPECT_EQ(params.format, bTooMuch.format);
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
new file mode 100644
index 0000000..b647aab
--- /dev/null
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/ProcessState.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <inttypes.h>
+
+namespace android {
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+static constexpr uint32_t INVALID_MASK = 0x10;
+class DisplayedContentSamplingTest : public ::testing::Test {
+protected:
+    void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(OK, mComposerClient->initCheck());
+        mDisplayToken = mComposerClient->getInternalDisplayToken();
+        ASSERT_TRUE(mDisplayToken);
+    }
+
+    bool shouldSkipTest() {
+        ui::PixelFormat format;
+        ui::Dataspace dataspace;
+        status_t status =
+                mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format,
+                                                                       &dataspace, &componentMask);
+        if (status == PERMISSION_DENIED) {
+            SUCCEED() << "permissions denial, skipping test";
+            return true;
+        }
+        if (status == INVALID_OPERATION) {
+            SUCCEED() << "optional function not supported, skipping test";
+            return true;
+        }
+        return false;
+    }
+
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<IBinder> mDisplayToken;
+    uint8_t componentMask = 0;
+};
+
+TEST_F(DisplayedContentSamplingTest, GetDisplayedContentSamplingAttributesAreSane) {
+    // tradefed infrastructure does not support use of GTEST_SKIP
+    if (shouldSkipTest()) return;
+
+    ui::PixelFormat format;
+    ui::Dataspace dataspace;
+    status_t status =
+            mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format,
+                                                                   &dataspace, &componentMask);
+    EXPECT_EQ(OK, status);
+    EXPECT_LE(componentMask, INVALID_MASK);
+}
+
+TEST_F(DisplayedContentSamplingTest, EnableWithInvalidMaskReturnsBadValue) {
+    if (shouldSkipTest()) return;
+
+    status_t status =
+            mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true, INVALID_MASK, 0);
+    EXPECT_EQ(BAD_VALUE, status);
+}
+
+TEST_F(DisplayedContentSamplingTest, EnableAndDisableSucceed) {
+    if (shouldSkipTest()) return;
+
+    status_t status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true,
+                                                                        componentMask, 10);
+    EXPECT_EQ(OK, status);
+
+    status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, false, componentMask,
+                                                               0);
+    EXPECT_EQ(OK, status);
+}
+
+TEST_F(DisplayedContentSamplingTest, SelectivelyDisableComponentOk) {
+    if (shouldSkipTest()) return;
+
+    status_t status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true,
+                                                                        componentMask, 0);
+    EXPECT_EQ(OK, status);
+
+    // Clear the lowest bit.
+    componentMask &= (componentMask - 1);
+    status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, false, componentMask,
+                                                               0);
+    EXPECT_EQ(OK, status);
+}
+
+TEST_F(DisplayedContentSamplingTest, SampleCollectionCoherentWithSupportMask) {
+    if (shouldSkipTest()) return;
+
+    DisplayedFrameStats stats;
+    status_t status = mComposerClient->getDisplayedContentSample(mDisplayToken, 0, 0, &stats);
+    EXPECT_EQ(OK, status);
+    if (stats.numFrames <= 0) return;
+
+    if (componentMask & (0x1 << 0)) EXPECT_NE(0, stats.component_0_sample.size());
+    if (componentMask & (0x1 << 1)) EXPECT_NE(0, stats.component_1_sample.size());
+    if (componentMask & (0x1 << 2)) EXPECT_NE(0, stats.component_2_sample.size());
+    if (componentMask & (0x1 << 3)) EXPECT_NE(0, stats.component_3_sample.size());
+}
+
+} // namespace android
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
new file mode 100644
index 0000000..ff1ba0a
--- /dev/null
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <poll.h>
+
+#include <memory>
+
+#include <android/native_window.h>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <input/InputWindow.h>
+#include <input/IInputFlinger.h>
+#include <input/InputTransport.h>
+#include <input/Input.h>
+
+#include <ui/DisplayInfo.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+
+namespace android {
+namespace test {
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+sp<IInputFlinger> getInputFlinger() {
+   sp<IBinder> input(defaultServiceManager()->getService(
+            String16("inputflinger")));
+    if (input == nullptr) {
+        ALOGE("Failed to link to input service");
+    } else { ALOGE("Linked to input"); }
+    return interface_cast<IInputFlinger>(input);
+}
+
+// We use the top 10 layers as a way to haphazardly place ourselves above anything else.
+static const int LAYER_BASE = INT32_MAX - 10;
+
+class InputSurface {
+public:
+    InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
+        mSurfaceControl = sc;
+
+        InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+        mServerChannel->setToken(new BBinder());
+
+        mInputFlinger = getInputFlinger();
+        mInputFlinger->registerInputChannel(mServerChannel);
+
+        populateInputInfo(width, height);
+
+        mInputConsumer = new InputConsumer(mClientChannel);
+    }
+
+    static std::unique_ptr<InputSurface> makeColorInputSurface(const sp<SurfaceComposerClient> &scc,
+                                                               int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
+                                   PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
+    static std::unique_ptr<InputSurface> makeBufferInputSurface(
+            const sp<SurfaceComposerClient> &scc, int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Buffer Surface"), width, height,
+                                   PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
+    static std::unique_ptr<InputSurface> makeContainerInputSurface(
+            const sp<SurfaceComposerClient> &scc, int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Container Surface"), 0 /* bufHeight */,
+                                   0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceContainer);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
+    InputEvent* consumeEvent() {
+        waitForEventAvailable();
+
+        InputEvent *ev;
+        uint32_t seqId;
+        status_t consumed = mInputConsumer->consume(&mInputEventFactory, true, -1, &seqId, &ev);
+        if (consumed != OK) {
+            return nullptr;
+        }
+        mInputConsumer->sendFinishedSignal(seqId, true);
+        return ev;
+    }
+
+    void expectTap(int x, int y) {
+        InputEvent* ev = consumeEvent();
+        EXPECT_TRUE(ev != nullptr);
+        EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+        MotionEvent* mev = static_cast<MotionEvent*>(ev);
+        EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
+        EXPECT_EQ(x, mev->getX(0));
+        EXPECT_EQ(y, mev->getY(0));
+
+        ev = consumeEvent();
+        EXPECT_TRUE(ev != nullptr);
+        EXPECT_TRUE(ev->getType() == AINPUT_EVENT_TYPE_MOTION);
+        mev = static_cast<MotionEvent*>(ev);
+        EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+    }
+
+    void expectMotionEvent(int motionEventType, int x, int y) {
+        InputEvent *ev = consumeEvent();
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION);
+        MotionEvent *mev = static_cast<MotionEvent *>(ev);
+        EXPECT_EQ(motionEventType, mev->getAction());
+        EXPECT_EQ(x, mev->getX(0));
+        EXPECT_EQ(y, mev->getY(0));
+    }
+
+    void expectNoMotionEvent(int motionEventType) {
+        InputEvent *ev = consumeEvent();
+        if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) {
+            // Didn't find an event or a motion event so assume action didn't occur.
+            return;
+        }
+
+        MotionEvent *mev = static_cast<MotionEvent *>(ev);
+        EXPECT_NE(motionEventType, mev->getAction());
+    }
+
+    ~InputSurface() {
+        mInputFlinger->unregisterInputChannel(mServerChannel);
+    }
+
+    void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
+                    const sp<SurfaceControl>&)> transactionBody) {
+        SurfaceComposerClient::Transaction t;
+        transactionBody(t, mSurfaceControl);
+        t.apply(true);
+    }
+
+    void showAt(int x, int y) {
+        SurfaceComposerClient::Transaction t;
+        t.show(mSurfaceControl);
+        t.setInputWindowInfo(mSurfaceControl, mInputInfo);
+        t.setLayer(mSurfaceControl, LAYER_BASE);
+        t.setPosition(mSurfaceControl, x, y);
+        t.setCrop_legacy(mSurfaceControl, Rect(0, 0, 100, 100));
+        t.setAlpha(mSurfaceControl, 1);
+        t.apply(true);
+    }
+
+private:
+    void waitForEventAvailable() {
+        struct pollfd fd;
+
+        fd.fd = mClientChannel->getFd();
+        fd.events = POLLIN;
+        poll(&fd, 1, 3000);
+    }
+
+    void populateInputInfo(int width, int height) {
+        mInputInfo.token = mServerChannel->getToken();
+        mInputInfo.name = "Test info";
+        mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
+        mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
+        mInputInfo.dispatchingTimeout = 100000;
+        mInputInfo.globalScaleFactor = 1.0;
+        mInputInfo.canReceiveKeys = true;
+        mInputInfo.hasFocus = true;
+        mInputInfo.hasWallpaper = false;
+        mInputInfo.paused = false;
+
+        mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
+
+        // TODO: Fill in from SF?
+        mInputInfo.ownerPid = 11111;
+        mInputInfo.ownerUid = 11111;
+        mInputInfo.inputFeatures = 0;
+        mInputInfo.displayId = 0;
+
+        InputApplicationInfo aInfo;
+        aInfo.token = new BBinder();
+        aInfo.name = "Test app info";
+        aInfo.dispatchingTimeout = 100000;
+
+        mInputInfo.applicationInfo = aInfo;
+    }
+public:
+    sp<SurfaceControl> mSurfaceControl;
+    sp<InputChannel> mServerChannel, mClientChannel;
+    sp<IInputFlinger> mInputFlinger;
+
+    InputWindowInfo mInputInfo;
+
+    PreallocatedInputEventFactory mInputEventFactory;
+    InputConsumer* mInputConsumer;
+};
+
+class InputSurfacesTest : public ::testing::Test {
+public:
+    InputSurfacesTest() {
+        ProcessState::self()->startThreadPool();
+    }
+
+    void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        const auto display = mComposerClient->getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        DisplayInfo info;
+        ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
+
+        // After a new buffer is queued, SurfaceFlinger is notified and will
+        // latch the new buffer on next vsync.  Let's heuristically wait for 3
+        // vsyncs.
+        mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
+    }
+
+    void TearDown() {
+        mComposerClient->dispose();
+    }
+
+    std::unique_ptr<InputSurface> makeSurface(int width, int height) {
+        return InputSurface::makeColorInputSurface(mComposerClient, width, height);
+    }
+
+    void postBuffer(const sp<SurfaceControl> &layer) {
+        // wait for previous transactions (such as setSize) to complete
+        Transaction().apply(true);
+        ANativeWindow_Buffer buffer = {};
+        EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+        ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+        // Request an empty transaction to get applied synchronously to ensure the buffer is
+        // latched.
+        Transaction().apply(true);
+        usleep(mBufferPostDelay);
+    }
+
+    sp<SurfaceComposerClient> mComposerClient;
+    int32_t mBufferPostDelay;
+};
+
+void injectTap(int x, int y) {
+    char *buf1, *buf2;
+    asprintf(&buf1, "%d", x);
+    asprintf(&buf2, "%d", y);
+    if (fork() == 0) {
+        execlp("input", "input", "tap", buf1, buf2, NULL);
+    }
+}
+
+void injectMotionEvent(std::string event, int x, int y) {
+    char *buf1, *buf2;
+    asprintf(&buf1, "%d", x);
+    asprintf(&buf2, "%d", y);
+    if (fork() == 0) {
+        execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL);
+    }
+}
+
+TEST_F(InputSurfacesTest, can_receive_input) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(100, 100);
+
+    injectTap(101, 101);
+
+    EXPECT_TRUE(surface->consumeEvent() != nullptr);
+}
+
+TEST_F(InputSurfacesTest, input_respects_positioning) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(100, 100);
+
+    std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+    surface2->showAt(200, 200);
+
+    injectTap(201, 201);
+    surface2->expectTap(1, 1);
+
+    injectTap(101, 101);
+    surface->expectTap(1, 1);
+
+    surface2->doTransaction([](auto &t, auto &sc) {
+         t.setPosition(sc, 100, 100);
+    });
+    surface->doTransaction([](auto &t, auto &sc) {
+         t.setPosition(sc, 200, 200);
+    });
+
+    injectTap(101, 101);
+    surface2->expectTap(1, 1);
+
+    injectTap(201, 201);
+    surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_layering) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+
+    surface->showAt(10, 10);
+    surface2->showAt(10, 10);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+         t.setLayer(sc, LAYER_BASE + 1);
+    });
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+
+    surface2->doTransaction([](auto &t, auto &sc) {
+         t.setLayer(sc, LAYER_BASE + 1);
+    });
+
+    injectTap(11, 11);
+    surface2->expectTap(1, 1);
+
+    surface2->doTransaction([](auto &t, auto &sc) {
+         t.hide(sc);
+    });
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+}
+
+// Surface Insets are set to offset the client content and draw a border around the client surface
+// (such as shadows in dialogs). Inputs sent to the client are offset such that 0,0 is the start
+// of the client content.
+TEST_F(InputSurfacesTest, input_respects_surface_insets) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+    bgSurface->showAt(100, 100);
+
+    fgSurface->mInputInfo.surfaceInset = 5;
+    fgSurface->showAt(100, 100);
+
+    injectTap(106, 106);
+    fgSurface->expectTap(1, 1);
+
+    injectTap(101, 101);
+    bgSurface->expectTap(1, 1);
+}
+
+// Ensure a surface whose insets are cropped, handles the touch offset correctly. ref:b/120413463
+TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) {
+    std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
+    parentSurface->showAt(100, 100);
+
+    childSurface->mInputInfo.surfaceInset = 10;
+    childSurface->showAt(100, 100);
+
+    childSurface->doTransaction([&](auto &t, auto &sc) {
+        t.setPosition(sc, -5, -5);
+        t.reparent(sc, parentSurface->mSurfaceControl->getHandle());
+    });
+
+    injectTap(106, 106);
+    childSurface->expectTap(1, 1);
+
+    injectTap(101, 101);
+    parentSurface->expectTap(1, 1);
+}
+
+// Ensure a surface whose insets are scaled, handles the touch offset correctly.
+TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+    bgSurface->showAt(100, 100);
+
+    fgSurface->mInputInfo.surfaceInset = 5;
+    fgSurface->showAt(100, 100);
+
+    fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 4.0); });
+
+    // expect = touch / scale - inset
+    injectTap(112, 124);
+    fgSurface->expectTap(1, 1);
+
+    injectTap(101, 101);
+    bgSurface->expectTap(1, 1);
+}
+
+// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
+TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->doTransaction([](auto &t, auto &sc) {
+        Region transparentRegion(Rect(0, 0, 10, 10));
+        t.setTransparentRegionHint(sc, transparentRegion);
+    });
+    surface->showAt(100, 100);
+    injectTap(101, 101);
+    surface->expectTap(1, 1);
+}
+
+// Ensure we send the input to the right surface when the surface visibility changes due to the
+// first buffer being submitted. ref: b/120839715
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> bufferSurface =
+            InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+
+    bgSurface->showAt(10, 10);
+    bufferSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+
+    postBuffer(bufferSurface->mSurfaceControl);
+    injectTap(11, 11);
+    bufferSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_buffer_layer_alpha) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> bufferSurface =
+            InputSurface::makeBufferInputSurface(mComposerClient, 100, 100);
+    postBuffer(bufferSurface->mSurfaceControl);
+
+    bgSurface->showAt(10, 10);
+    bufferSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    bufferSurface->expectTap(1, 1);
+
+    bufferSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+
+    bgSurface->showAt(10, 10);
+    fgSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    fgSurface->expectTap(1, 1);
+
+    fgSurface->doTransaction([](auto &t, auto &sc) { t.setAlpha(sc, 0.0); });
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) {
+    std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
+    std::unique_ptr<InputSurface> containerSurface =
+            InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+
+    bgSurface->showAt(10, 10);
+    containerSurface->showAt(10, 10);
+
+    injectTap(11, 11);
+    containerSurface->expectTap(1, 1);
+
+    containerSurface->doTransaction([](auto &t, auto &sc) { t.hide(sc); });
+
+    injectTap(11, 11);
+    bgSurface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, transfer_touch_focus) {
+    std::unique_ptr<InputSurface> fromSurface = makeSurface(100, 100);
+
+    fromSurface->showAt(10, 10);
+    injectMotionEvent("DOWN", 11, 11);
+    fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1);
+
+    std::unique_ptr<InputSurface> toSurface = makeSurface(100, 100);
+    toSurface->showAt(10, 10);
+
+    sp<IBinder> fromToken = fromSurface->mServerChannel->getToken();
+    sp<IBinder> toToken = toSurface->mServerChannel->getToken();
+    SurfaceComposerClient::Transaction t;
+    t.transferTouchFocus(fromToken, toToken).apply(true);
+
+    injectMotionEvent("UP", 11, 11);
+    toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
+    fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
+}
+
+TEST_F(InputSurfacesTest, input_respects_outscreen) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(-1, -1);
+
+    injectTap(0, 0);
+    surface->expectTap(1, 1);
+}
+}
+}
diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp
index ccd674f..b60995a 100644
--- a/libs/gui/tests/FillBuffer.cpp
+++ b/libs/gui/tests/FillBuffer.cpp
@@ -93,11 +93,11 @@
     android_native_buffer_t* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
             (void**)(&img)));
     fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index a91552f..a1405fc 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -50,7 +50,7 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
     char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
-    if (displaySecsEnv != NULL) {
+    if (displaySecsEnv != nullptr) {
         mDisplaySecs = atoi(displaySecsEnv);
         if (mDisplaySecs < 0) {
             mDisplaySecs = 0;
@@ -67,7 +67,7 @@
                 String8("Test Surface"), getSurfaceWidth(), getSurfaceHeight(),
                 PIXEL_FORMAT_RGB_888, 0);
 
-        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl != nullptr);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
         Transaction t;
@@ -117,7 +117,7 @@
         sleep(mDisplaySecs);
     }
 
-    if (mComposerClient != NULL) {
+    if (mComposerClient != nullptr) {
         mComposerClient->dispose();
     }
     if (mEglContext != EGL_NO_CONTEXT) {
@@ -171,7 +171,7 @@
 
 EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
                                        sp<ANativeWindow>& window) const {
-    return eglCreateWindowSurface(display, config, window.get(), NULL);
+    return eglCreateWindowSurface(display, config, window.get(), nullptr);
 }
 
 ::testing::AssertionResult GLTest::checkPixel(int x, int y,
@@ -256,7 +256,7 @@
     GLuint shader = glCreateShader(shaderType);
     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
     if (shader) {
-        glShaderSource(shader, 1, &pSource, NULL);
+        glShaderSource(shader, 1, &pSource, nullptr);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
         glCompileShader(shader);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
@@ -270,7 +270,7 @@
             if (infoLen) {
                 char* buf = (char*) malloc(infoLen);
                 if (buf) {
-                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    glGetShaderInfoLog(shader, infoLen, nullptr, buf);
                     printf("Shader compile log:\n%s\n", buf);
                     free(buf);
                     FAIL();
@@ -278,7 +278,7 @@
             } else {
                 char* buf = (char*) malloc(0x1000);
                 if (buf) {
-                    glGetShaderInfoLog(shader, 0x1000, NULL, buf);
+                    glGetShaderInfoLog(shader, 0x1000, nullptr, buf);
                     printf("Shader compile log:\n%s\n", buf);
                     free(buf);
                     FAIL();
@@ -322,7 +322,7 @@
             if (bufLength) {
                 char* buf = (char*) malloc(bufLength);
                 if (buf) {
-                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    glGetProgramInfoLog(program, bufLength, nullptr, buf);
                     printf("Program link log:\n%s\n", buf);
                     free(buf);
                     FAIL();
diff --git a/libs/gui/tests/GLTest.h b/libs/gui/tests/GLTest.h
index f0d27a8..f290b3c 100644
--- a/libs/gui/tests/GLTest.h
+++ b/libs/gui/tests/GLTest.h
@@ -39,7 +39,7 @@
             mEglDisplay(EGL_NO_DISPLAY),
             mEglSurface(EGL_NO_SURFACE),
             mEglContext(EGL_NO_CONTEXT),
-            mGlConfig(NULL) {
+            mGlConfig(nullptr) {
     }
 
     virtual void SetUp();
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index a35cf11..aef7aed 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -228,9 +228,9 @@
     void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
             sp<GraphicBuffer> *buffer)
     {
-        ASSERT_TRUE(slot != NULL);
-        ASSERT_TRUE(fence != NULL);
-        ASSERT_TRUE(buffer != NULL);
+        ASSERT_TRUE(slot != nullptr);
+        ASSERT_TRUE(fence != nullptr);
+        ASSERT_TRUE(buffer != nullptr);
 
         ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
@@ -263,7 +263,7 @@
     EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN,
                                             TEST_API,
                                             TEST_CONTROLLED_BY_APP,
-                                            /*output*/NULL));
+                                            /*output*/nullptr));
 
     // Invalid API returns bad value
     EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN,
@@ -359,7 +359,7 @@
     // TODO: Consider documented the above enums as unsupported or make a new enum for IGBP
 
     // Value was NULL
-    EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/NULL));
+    EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/nullptr));
 
     ASSERT_OK(mConsumer->consumerDisconnect());
 
@@ -465,7 +465,7 @@
 
     // Fence was NULL
     {
-        sp<Fence> nullFence = NULL;
+        sp<Fence> nullFence = nullptr;
 
         IGraphicBufferProducer::QueueBufferInput input =
                 QueueBufferInputBuilder().setFence(nullFence).build();
@@ -695,10 +695,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
-        ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
-    }
+    ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
 }
 
 TEST_P(IGraphicBufferProducerTest,
@@ -735,10 +732,7 @@
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
-        ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
-    }
+    ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
 }
 
 TEST_P(IGraphicBufferProducerTest,
@@ -778,18 +772,29 @@
     sp<GraphicBuffer> buffer;
 
     setupDequeueRequestBuffer(&slot, &fence, &buffer);
+    ASSERT_TRUE(buffer != nullptr);
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
-        ASSERT_OK(mProducer->detachBuffer(slot));
-    }
+    ASSERT_OK(mProducer->detachBuffer(slot));
+    EXPECT_OK(buffer->initCheck());
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/69981968): Implement BufferHubProducer::attachBuffer
-        ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
-    }
+    ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+}
+
+TEST_P(IGraphicBufferProducerTest, DetachThenAttach_Succeeds) {
+    int slot = -1;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    setupDequeueRequestBuffer(&slot, &fence, &buffer);
+    ASSERT_TRUE(buffer != nullptr);
+
+    ASSERT_OK(mProducer->detachBuffer(slot));
+    EXPECT_OK(buffer->initCheck());
+
+    EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
+    EXPECT_OK(buffer->initCheck());
 }
 
 #if USE_BUFFER_HUB_AS_BUFFER_QUEUE
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index bb6b8a5..acd4297 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -27,7 +27,7 @@
 
 class ProxyBQP : public BnGraphicBufferProducer {
 public:
-    ProxyBQP(const sp<IGraphicBufferProducer>& producer) : mProducer(producer) {}
+    explicit ProxyBQP(const sp<IGraphicBufferProducer>& producer) : mProducer(producer) {}
 
     // Pass through calls to mProducer
     status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
@@ -102,7 +102,7 @@
 
 class MaliciousBQP : public ProxyBQP {
 public:
-    MaliciousBQP(const sp<IGraphicBufferProducer>& producer) : ProxyBQP(producer) {}
+    explicit MaliciousBQP(const sp<IGraphicBufferProducer>& producer) : ProxyBQP(producer) {}
 
     void beMalicious(int32_t value) { mMaliciousValue = value; }
 
diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp
index 3a25ac5..7d3d4aa 100644
--- a/libs/gui/tests/MultiTextureConsumer_test.cpp
+++ b/libs/gui/tests/MultiTextureConsumer_test.cpp
@@ -47,7 +47,7 @@
         GLTest::TearDown();
     }
     virtual EGLint const* getContextAttribs() {
-        return NULL;
+        return nullptr;
     }
     virtual EGLint const* getConfigAttribs() {
         static EGLint sDefaultConfigAttribs[] = {
@@ -105,7 +105,7 @@
 
     glClear(GL_COLOR_BUFFER_BIT);
     for (int i=0 ; i<8 ; i++) {
-        mSurface->lock(&buffer, NULL);
+        mSurface->lock(&buffer, nullptr);
         memset(buffer.bits, (i&7) * 0x20, buffer.stride * buffer.height * 4);
         mSurface->unlockAndPost();
 
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
new file mode 100644
index 0000000..d33ecfb
--- /dev/null
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <binder/ProcessState.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Looper.h>
+
+using namespace std::chrono_literals;
+
+namespace android::test {
+
+struct ChoreographerSync {
+    ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
+    ~ChoreographerSync() = default;
+
+    void notify() const {
+        std::unique_lock<decltype(mutex_)> lk(mutex_);
+
+        auto check_event = [](auto const& ev) -> bool {
+            return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+        };
+        DisplayEventReceiver::Event ev_;
+        int evs = receiver_.getEvents(&ev_, 1);
+        auto vsync_event_found = check_event(ev_);
+        while (evs) {
+            evs = receiver_.getEvents(&ev_, 1);
+            vsync_event_found |= check_event(ev_);
+        }
+
+        if (vsync_event_found) {
+            notification_arrived_ = true;
+            cv_.notify_all();
+        }
+    }
+
+    void wait_vsync_notify() const {
+        std::unique_lock<decltype(mutex_)> lk(mutex_);
+        cv_.wait(lk, [this] { return notification_arrived_; });
+        notification_arrived_ = false;
+    }
+
+private:
+    ChoreographerSync(ChoreographerSync const&) = delete;
+    ChoreographerSync& operator=(ChoreographerSync const&) = delete;
+
+    std::mutex mutable mutex_;
+    std::condition_variable mutable cv_;
+    bool mutable notification_arrived_ = false;
+    DisplayEventReceiver& receiver_;
+};
+
+struct ChoreographerSim {
+    static std::unique_ptr<ChoreographerSim> make() {
+        auto receiver = std::make_unique<DisplayEventReceiver>();
+        if (!receiver || receiver->initCheck() == NO_INIT) {
+            ALOGE("No display reciever");
+            return nullptr;
+        }
+        return std::unique_ptr<ChoreographerSim>(new ChoreographerSim(std::move(receiver)));
+    }
+
+    ~ChoreographerSim() {
+        poll_ = false;
+        looper->wake();
+        choreographer_thread_.join();
+    }
+
+    void request_render_wait(std::function<void()> const& render_fn) {
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+        render_fn();
+
+        // Purpose is to make sure that the content is latched by the time we sample.
+        // Waiting one vsync after queueing could still race with vsync, so wait for two, after
+        // which the content is pretty reliably on screen.
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+    }
+
+private:
+    ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
+          : display_event_receiver_{std::move(receiver)},
+            choreographer_{*display_event_receiver_},
+            looper{new Looper(false)} {
+        choreographer_thread_ = std::thread([this] {
+            auto vsync_notify_fd = display_event_receiver_->getFd();
+            looper->addFd(vsync_notify_fd, 0, Looper::EVENT_INPUT,
+                          [](int /*fd*/, int /*events*/, void* data) -> int {
+                              if (!data) return 0;
+                              reinterpret_cast<ChoreographerSync*>(data)->notify();
+                              return 1;
+                          },
+                          const_cast<void*>(reinterpret_cast<void const*>(&choreographer_)));
+
+            while (poll_) {
+                auto const poll_interval =
+                        std::chrono::duration_cast<std::chrono::milliseconds>(1s).count();
+                auto rc = looper->pollOnce(poll_interval);
+                if ((rc != Looper::POLL_CALLBACK) && (rc != Looper::POLL_WAKE))
+                    ALOGW("Vsync Looper returned: %i\n", rc);
+            }
+        });
+    }
+
+    ChoreographerSim(ChoreographerSim const&) = delete;
+    ChoreographerSim& operator=(ChoreographerSim const&) = delete;
+
+    std::unique_ptr<DisplayEventReceiver> const display_event_receiver_;
+    ChoreographerSync const choreographer_;
+    sp<Looper> looper;
+    std::thread choreographer_thread_;
+    std::atomic<bool> poll_{true};
+};
+
+struct Listener : BnRegionSamplingListener {
+    void onSampleCollected(float medianLuma) override {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        received = true;
+        mLuma = medianLuma;
+        cv.notify_all();
+    };
+    bool wait_event(std::chrono::milliseconds timeout) {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        return cv.wait_for(lk, timeout, [this] { return received; });
+    }
+
+    float luma() {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        return mLuma;
+    }
+
+    void reset() {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        received = false;
+    }
+
+private:
+    std::condition_variable cv;
+    std::mutex mutex;
+    bool received = false;
+    float mLuma = -0.0f;
+};
+
+// Hoisted to TestSuite setup to avoid flake in test (b/124675919)
+std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
+
+struct RegionSamplingTest : ::testing::Test {
+protected:
+    RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
+
+    static void SetUpTestSuite() {
+        gChoreographerSim = ChoreographerSim::make();
+        ASSERT_NE(gChoreographerSim, nullptr);
+    }
+
+    void SetUp() override {
+        mSurfaceComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
+
+        mBackgroundLayer =
+                mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
+                                                      0, PIXEL_FORMAT_RGBA_8888,
+                                                      ISurfaceComposerClient::eFXSurfaceColor);
+        uint32_t layerPositionBottom = 0x7E000000;
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mBackgroundLayer, layerPositionBottom)
+                .setPosition(mBackgroundLayer, 100, 100)
+                .setColor(mBackgroundLayer, half3{0.5, 0.5, 0.5})
+                .show(mBackgroundLayer)
+                .apply();
+
+        mContentLayer = mSurfaceComposerClient->createSurface(String8("Content RegionSamplingTest"),
+                                                              300, 300, PIXEL_FORMAT_RGBA_8888, 0);
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mContentLayer, layerPositionBottom + 1)
+                .setPosition(mContentLayer, 100, 100)
+                .setColor(mContentLayer, half3{0.5, 0.5, 0.5})
+                .show(mContentLayer)
+                .apply();
+
+        mTopLayer = mSurfaceComposerClient->createSurface(String8("TopLayer RegionSamplingTest"), 0,
+                                                          0, PIXEL_FORMAT_RGBA_8888, 0);
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mTopLayer, layerPositionBottom + 2)
+                .setPosition(mTopLayer, 0, 0)
+                .show(mBackgroundLayer)
+                .apply();
+    }
+
+    void fill_render(uint32_t rgba_value) {
+        auto surface = mContentLayer->getSurface();
+        ANativeWindow_Buffer outBuffer;
+        status_t status = surface->lock(&outBuffer, NULL);
+        ASSERT_EQ(status, android::OK);
+        auto b = reinterpret_cast<uint32_t*>(outBuffer.bits);
+        for (auto i = 0; i < outBuffer.height; i++) {
+            for (auto j = 0; j < outBuffer.width; j++) {
+                b[j] = rgba_value;
+            }
+            b += outBuffer.stride;
+        }
+
+        gChoreographerSim->request_render_wait([&surface] { surface->unlockAndPost(); });
+    }
+
+    sp<SurfaceComposerClient> mSurfaceComposerClient;
+    sp<SurfaceControl> mBackgroundLayer;
+    sp<SurfaceControl> mContentLayer;
+    sp<SurfaceControl> mTopLayer;
+
+    uint32_t const rgba_green = 0xFF00FF00;
+    float const luma_green = 0.7152;
+    uint32_t const rgba_blue = 0xFFFF0000;
+    float const luma_blue = 0.0722;
+    float const error_margin = 0.01;
+    float const luma_gray = 0.50;
+};
+
+TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
+    fill_render(rgba_green);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+    EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) {
+    fill_render(rgba_green);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+    EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+    listener->reset();
+
+    fill_render(rgba_blue);
+    EXPECT_TRUE(listener->wait_event(300ms))
+            << "timed out waiting for 2nd luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) {
+    fill_render(rgba_green);
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> greenListener = new Listener();
+    const Rect greenSampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
+
+    sp<Listener> grayListener = new Listener();
+    const Rect graySampleArea{500, 100, 600, 200};
+    composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
+
+    EXPECT_TRUE(grayListener->wait_event(300ms))
+            << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
+    EXPECT_TRUE(greenListener->wait_event(300ms))
+            << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
+
+    composer->removeRegionSamplingListener(greenListener);
+    composer->removeRegionSamplingListener(grayListener);
+}
+
+} // namespace android::test
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
new file mode 100644
index 0000000..9891587
--- /dev/null
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "SamplingTest"
+
+#include <chrono>
+#include <thread>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+class Button : public BnRegionSamplingListener {
+public:
+    Button(const char* name, const Rect& samplingArea) {
+        sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+
+        mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                        ISurfaceComposerClient::eFXSurfaceColor);
+
+        const int32_t width = samplingArea.getWidth();
+        const int32_t height = samplingArea.getHeight();
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mButton, 0x7fffffff)
+                .setCrop_legacy(mButton,
+                                {0, 0, width - 2 * BUTTON_PADDING, height - 2 * BUTTON_PADDING})
+                .setPosition(mButton, samplingArea.left + BUTTON_PADDING,
+                             samplingArea.top + BUTTON_PADDING)
+                .setColor(mButton, half3{1, 1, 1})
+                .show(mButton)
+                .apply();
+
+        mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                             ISurfaceComposerClient::eFXSurfaceColor);
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mButtonBlend, 0x7ffffffe)
+                .setCrop_legacy(mButtonBlend,
+                                {0, 0, width - 2 * SAMPLE_AREA_PADDING,
+                                 height - 2 * SAMPLE_AREA_PADDING})
+                .setPosition(mButtonBlend, samplingArea.left + SAMPLE_AREA_PADDING,
+                             samplingArea.top + SAMPLE_AREA_PADDING)
+                .setColor(mButtonBlend, half3{1, 1, 1})
+                .setAlpha(mButtonBlend, 0.2)
+                .show(mButtonBlend)
+                .apply(true);
+
+        const bool HIGHLIGHT_SAMPLING_AREA = false;
+        if (HIGHLIGHT_SAMPLING_AREA) {
+            mSamplingArea =
+                    client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                          ISurfaceComposerClient::eFXSurfaceColor);
+
+            SurfaceComposerClient::Transaction{}
+                    .setLayer(mSamplingArea, 0x7ffffffd)
+                    .setCrop_legacy(mSamplingArea, {0, 0, 100, 32})
+                    .setPosition(mSamplingArea, 490, 1606)
+                    .setColor(mSamplingArea, half3{0, 1, 0})
+                    .setAlpha(mSamplingArea, 0.1)
+                    .show(mSamplingArea)
+                    .apply();
+        }
+    }
+
+    sp<IBinder> getStopLayerHandle() { return mButtonBlend->getHandle(); }
+
+private:
+    static const int32_t BLEND_WIDTH = 2;
+    static const int32_t SAMPLE_AREA_PADDING = 8;
+    static const int32_t BUTTON_PADDING = BLEND_WIDTH + SAMPLE_AREA_PADDING;
+
+    void setColor(float color) {
+        const float complement = std::fmod(color + 0.5f, 1.0f);
+        SurfaceComposerClient::Transaction{}
+                .setColor(mButton, half3{complement, complement, complement})
+                .setColor(mButtonBlend, half3{color, color, color})
+                .apply();
+    }
+
+    void onSampleCollected(float medianLuma) override {
+        ATRACE_CALL();
+        setColor(medianLuma);
+    }
+
+    sp<SurfaceComposerClient> mClient;
+    sp<SurfaceControl> mButton;
+    sp<SurfaceControl> mButtonBlend;
+    sp<SurfaceControl> mSamplingArea;
+};
+
+} // namespace android
+
+using namespace android;
+
+int main(int, const char**) {
+    const Rect homeButtonArea{490, 1606, 590, 1654};
+    sp<android::Button> homeButton = new android::Button("HomeButton", homeButtonArea);
+    const Rect backButtonArea{200, 1606, 248, 1654};
+    sp<android::Button> backButton = new android::Button("BackButton", backButtonArea);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(),
+                                        homeButton);
+    composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(),
+                                        backButton);
+
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+
+    return 0;
+}
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d5b2f00..65e09f2 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -29,7 +29,6 @@
 #include <utils/Thread.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
 
 namespace android {
 
@@ -39,7 +38,7 @@
             mEglDisplay(EGL_NO_DISPLAY),
             mEglSurface(EGL_NO_SURFACE),
             mEglContext(EGL_NO_CONTEXT),
-            mEglConfig(NULL) {
+            mEglConfig(nullptr) {
     }
 
     virtual void SetUp() {
@@ -82,7 +81,7 @@
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
 
-        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, 0);
+        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, nullptr);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
 
@@ -127,7 +126,7 @@
 
 TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) {
     sp<IGraphicBufferProducer> ist(mSTC->getIGraphicBufferProducer());
-    ASSERT_TRUE(ist != NULL);
+    ASSERT_TRUE(ist != nullptr);
 }
 
 TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
@@ -155,7 +154,7 @@
     EXPECT_TRUE(eglInitialize(dpy, &majorVersion, &minorVersion));
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
-    EGLConfig myConfig = {0};
+    EGLConfig myConfig = {nullptr};
     EGLint numConfigs = 0;
     EGLint configAttribs[] = {
         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
@@ -172,7 +171,7 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
     EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, mANW.get(),
-            NULL);
+            nullptr);
     EXPECT_NE(EGL_NO_SURFACE, eglSurface);
     EXPECT_EQ(EGL_SUCCESS, eglGetError());
 
@@ -185,7 +184,7 @@
 
 TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) {
 
-    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), NULL);
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), nullptr);
     EXPECT_NE(EGL_NO_SURFACE, eglSurface);
     EXPECT_EQ(EGL_SUCCESS, eglGetError());
 
@@ -638,18 +637,6 @@
 }
 
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
-    // Query to see if the image crop extension exists
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
-    bool atEnd = (cropExtLen+1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
-
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
     android_native_rect_t crop;
@@ -669,17 +656,15 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // If the egl image crop extension is not present, this accounts for the
-    // .5 texel shrink for each edge that's included in the transform matrix
-    // to avoid texturing outside the crop region. Otherwise the crop is not
-    // included in the transform matrix.
-    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
+    // This accounts for the .5 texel shrink for each edge that's included in
+    // the transform matrix to avoid texturing outside the crop region.
+    EXPECT_EQ(0.5f, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
+    EXPECT_EQ(-0.5f, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -688,8 +673,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
-    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
+    EXPECT_EQ(0.0625f, mtx[12]);
+    EXPECT_EQ(0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
@@ -753,7 +738,7 @@
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
         mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
-                0);
+                nullptr);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
 
@@ -765,7 +750,7 @@
                     GLConsumer::TEXTURE_EXTERNAL, true, false));
             sp<Surface> stc(new Surface(producer));
             mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
-                    static_cast<ANativeWindow*>(stc.get()), NULL);
+                    static_cast<ANativeWindow*>(stc.get()), nullptr);
             ASSERT_EQ(EGL_SUCCESS, eglGetError());
             ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
         }
diff --git a/libs/gui/tests/SurfaceTextureFBO.h b/libs/gui/tests/SurfaceTextureFBO.h
index 7f1ae84..70f988d 100644
--- a/libs/gui/tests/SurfaceTextureFBO.h
+++ b/libs/gui/tests/SurfaceTextureFBO.h
@@ -34,7 +34,7 @@
         glGenTextures(1, &mFboTex);
         glBindTexture(GL_TEXTURE_2D, mFboTex);
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
-                getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+                getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
         glBindTexture(GL_TEXTURE_2D, 0);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
 
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index 0134273..f34561f 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -39,12 +39,12 @@
     android_native_buffer_t* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with green
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
             0, 255);
@@ -63,7 +63,7 @@
 
         ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
                 &anb));
-        ASSERT_TRUE(anb != NULL);
+        ASSERT_TRUE(anb != nullptr);
 
         buf = GraphicBuffer::from(anb);
 
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL.h b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
index 2ce20eb..03975b1 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
@@ -158,7 +158,7 @@
     }
 
     virtual void TearDown() {
-        if (mProducerThread != NULL) {
+        if (mProducerThread != nullptr) {
             mProducerThread->requestExitAndWait();
         }
         mProducerThread.clear();
@@ -167,7 +167,7 @@
     }
 
     void runProducerThread(const sp<ProducerThread> producerThread) {
-        ASSERT_TRUE(mProducerThread == NULL);
+        ASSERT_TRUE(mProducerThread == nullptr);
         mProducerThread = producerThread;
         producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
                 mProducerEglContext);
diff --git a/libs/gui/tests/SurfaceTextureGLToGL.h b/libs/gui/tests/SurfaceTextureGLToGL.h
index 5d43a48..3a87c12 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLToGL.h
@@ -38,7 +38,7 @@
 
     void SetUpWindowAndContext() {
         mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                mANW.get(), NULL);
+                mANW.get(), nullptr);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
 
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 5639286..e2b4f3d 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -40,12 +40,12 @@
     ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
     buf->unlock();
@@ -90,12 +90,12 @@
     ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
     buf->unlock();
@@ -155,11 +155,11 @@
         ANativeWindowBuffer* anb;
         ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
                 &anb));
-        ASSERT_TRUE(anb != NULL);
+        ASSERT_TRUE(anb != nullptr);
 
         sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
-        uint8_t* img = NULL;
+        uint8_t* img = nullptr;
         buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
         fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
         buf->unlock();
@@ -234,7 +234,7 @@
                         &anb) != NO_ERROR) {
                     return false;
                 }
-                if (anb == NULL) {
+                if (anb == nullptr) {
                     return false;
                 }
 
@@ -248,7 +248,7 @@
                 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
                 int yuvTexStrideU = yuvTexStrideV;
 
-                uint8_t* img = NULL;
+                uint8_t* img = nullptr;
                 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
 
                 // Gray out all the test pixels first, so we're more likely to
@@ -457,7 +457,7 @@
                         &anb) != NO_ERROR) {
                     return false;
                 }
-                if (anb == NULL) {
+                if (anb == nullptr) {
                     return false;
                 }
                 if (mANW->queueBuffer(mANW.get(), anb, -1)
@@ -641,7 +641,7 @@
                     &anb) != NO_ERROR) {
                 return false;
             }
-            if (anb == NULL) {
+            if (anb == nullptr) {
                 return false;
             }
             if (mANW->queueBuffer(mANW.get(), anb, -1)
@@ -654,7 +654,7 @@
                     &anb) != NO_ERROR) {
                 return false;
             }
-            if (anb == NULL) {
+            if (anb == nullptr) {
                 return false;
             }
             if (mANW->queueBuffer(mANW.get(), anb, -1)
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 04686e5..960cf18 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -72,7 +72,7 @@
         mSurfaceControl = mComposerClient->createSurface(
                 String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
 
-        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl != nullptr);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
         Transaction t;
@@ -81,7 +81,7 @@
                 .apply());
 
         mSurface = mSurfaceControl->getSurface();
-        ASSERT_TRUE(mSurface != NULL);
+        ASSERT_TRUE(mSurface != nullptr);
     }
 
     virtual void TearDown() {
@@ -131,12 +131,15 @@
 
     // Verify the screenshot works with no protected buffers.
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    sp<IBinder> display(sf->getBuiltInDisplay(
-            ISurfaceComposer::eDisplayIdMain));
+
+    const sp<IBinder> display = sf->getInternalDisplayToken();
+    ASSERT_FALSE(display == nullptr);
+
     sp<GraphicBuffer> outBuffer;
     bool ignored;
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, ignored, Rect(),
-            64, 64, 0, 0x7fffffff, false));
+    ASSERT_EQ(NO_ERROR,
+              sf->captureScreen(display, &outBuffer, ignored, ui::Dataspace::V0_SRGB,
+                                ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
 
     ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
             NATIVE_WINDOW_API_CPU));
@@ -146,7 +149,7 @@
     ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
             GRALLOC_USAGE_PROTECTED));
     ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
-    ANativeWindowBuffer* buf = 0;
+    ANativeWindowBuffer* buf = nullptr;
 
     status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf);
     if (err) {
@@ -166,8 +169,9 @@
                 &buf));
         ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
     }
-    ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, ignored, Rect(),
-            64, 64, 0, 0x7fffffff, false));
+    ASSERT_EQ(NO_ERROR,
+              sf->captureScreen(display, &outBuffer, ignored, ui::Dataspace::V0_SRGB,
+                                ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false));
 }
 
 TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
@@ -206,7 +210,7 @@
 }
 
 TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) {
-    const android_dataspace TEST_DATASPACE = HAL_DATASPACE_SRGB;
+    const android_dataspace TEST_DATASPACE = HAL_DATASPACE_V0_SRGB;
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
@@ -365,10 +369,17 @@
         78.0,
         62.0,
     };
+
+    std::vector<uint8_t> hdr10plus;
+    hdr10plus.push_back(0xff);
+
     int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086);
     ASSERT_EQ(error, NO_ERROR);
     error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3);
     ASSERT_EQ(error, NO_ERROR);
+    error = native_window_set_buffers_hdr10_plus_metadata(window.get(), hdr10plus.size(),
+                                                          hdr10plus.data());
+    ASSERT_EQ(error, NO_ERROR);
 }
 
 TEST_F(SurfaceTest, DynamicSetBufferCount) {
@@ -537,10 +548,6 @@
     }
 
     sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
-    sp<ISurfaceComposerClient> createScopedConnection(
-            const sp<IGraphicBufferProducer>& /* parent */) override {
-        return nullptr;
-    }
     sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
             override {
         return nullptr;
@@ -548,10 +555,16 @@
     sp<IBinder> createDisplay(const String8& /*displayName*/,
             bool /*secure*/) override { return nullptr; }
     void destroyDisplay(const sp<IBinder>& /*display */) override {}
-    sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
+    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
+    sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
     void setTransactionState(const Vector<ComposerState>& /*state*/,
-            const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/)
-            override {}
+                             const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
+                             const sp<IBinder>& /*applyToken*/,
+                             const InputWindowCommands& /*inputWindowCommands*/,
+                             int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/,
+                             const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
+    }
+
     void bootFinished() override {}
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& /*surface*/) const override {
@@ -582,9 +595,6 @@
             Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
     status_t getDisplayStats(const sp<IBinder>& /*display*/,
             DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
-    status_t getDisplayViewport(const sp<IBinder>& /*display*/, Rect* /*outViewport*/) override {
-        return NO_ERROR;
-    }
     int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
     status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
             override {
@@ -594,23 +604,36 @@
             Vector<ColorMode>* /*outColorModes*/) override {
         return NO_ERROR;
     }
+    status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
+            ui::DisplayPrimaries& /*primaries*/) override {
+        return NO_ERROR;
+    }
     ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
             override {
         return ColorMode::NATIVE;
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
-    status_t captureScreen(const sp<IBinder>& /*display*/,
-            sp<GraphicBuffer>* /*outBuffer*/,
-            bool& /* outCapturedSecureLayers */,
-            Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
-            int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/,
-            bool /*useIdentityTransform*/,
-            Rotation /*rotation*/,
-            bool /*captureSecureLayers*/) override { return NO_ERROR; }
-    virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
-                                   sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/,
-                                   float /*frameScale*/, bool /*childrenOnly*/) override {
+    status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
+                           bool& /* outCapturedSecureLayers */,
+                           const ui::Dataspace /*reqDataspace*/,
+                           const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
+                           uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+                           bool /*useIdentityTransform*/, Rotation /*rotation*/,
+                           bool /*captureSecureLayers*/) override {
+        return NO_ERROR;
+    }
+    status_t captureScreen(uint64_t /*displayOrLayerStack*/, ui::Dataspace* /*outDataspace*/,
+                           sp<GraphicBuffer>* /*outBuffer*/) override {
+        return NO_ERROR;
+    }
+    virtual status_t captureLayers(
+            const sp<IBinder>& /*parentHandle*/, sp<GraphicBuffer>* /*outBuffer*/,
+            const ui::Dataspace /*reqDataspace*/, const ui::PixelFormat /*reqPixelFormat*/,
+            const Rect& /*sourceCrop*/,
+            const std::unordered_set<sp<IBinder>,
+                                     ISurfaceComposer::SpHash<IBinder>>& /*excludeHandles*/,
+            float /*frameScale*/, bool /*childrenOnly*/) override {
         return NO_ERROR;
     }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
@@ -628,6 +651,60 @@
     status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
         return NO_ERROR;
     }
+    status_t getCompositionPreference(
+            ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/,
+            ui::Dataspace* /*outWideColorGamutDataspace*/,
+            ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override {
+        return NO_ERROR;
+    }
+    status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& /*display*/,
+                                                   ui::PixelFormat* /*outFormat*/,
+                                                   ui::Dataspace* /*outDataspace*/,
+                                                   uint8_t* /*outComponentMask*/) const override {
+        return NO_ERROR;
+    }
+    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/,
+                                              uint8_t /*componentMask*/,
+                                              uint64_t /*maxFrames*/) const override {
+        return NO_ERROR;
+    }
+    status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/,
+                                       uint64_t /*timestamp*/,
+                                       DisplayedFrameStats* /*outStats*/) const override {
+        return NO_ERROR;
+    }
+
+    status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
+    status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
+
+    status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
+    status_t getDisplayBrightnessSupport(const sp<IBinder>& /*displayToken*/,
+                                         bool* /*outSupport*/) const override {
+        return NO_ERROR;
+    }
+    status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
+                                  float /*brightness*/) const override {
+        return NO_ERROR;
+    }
+
+    status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
+                                       const sp<IBinder>& /*stopLayerHandle*/,
+                                       const sp<IRegionSamplingListener>& /*listener*/) override {
+        return NO_ERROR;
+    }
+    status_t removeRegionSamplingListener(
+            const sp<IRegionSamplingListener>& /*listener*/) override {
+        return NO_ERROR;
+    }
+    status_t setAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
+                                      const std::vector<int32_t>& /*allowedConfigs*/) override {
+        return NO_ERROR;
+    }
+    status_t getAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
+                                      std::vector<int32_t>* /*outAllowedConfigs*/) override {
+        return NO_ERROR;
+    }
+    status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
@@ -638,8 +715,7 @@
 
 class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
 public:
-    FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap)
-        : mFenceMap(fenceMap) {}
+    explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
 
     ~FakeProducerFrameEventHistory() {}
 
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
new file mode 100644
index 0000000..63411b9
--- /dev/null
+++ b/libs/incidentcompanion/Android.bp
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+filegroup {
+    name: "incidentcompanion_aidl",
+    srcs: [
+        "binder/android/os/IIncidentAuthListener.aidl",
+        "binder/android/os/IIncidentCompanion.aidl",
+    ],
+    path: "binder",
+}
+
+cc_library_static {
+    name: "libincidentcompanion",
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    aidl: {
+        local_include_dirs: ["binder"],
+        export_aidl_headers: true,
+    },
+    srcs: [
+        ":incidentcompanion_aidl",
+        "src/IncidentManager.cpp",
+    ],
+    export_include_dirs: [
+        "binder",
+        "include",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+}
+
diff --git a/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl b/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
new file mode 100644
index 0000000..5484be8
--- /dev/null
+++ b/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Callback for IIncidentCompanion.
+ *
+ * @hide
+ */
+oneway interface IIncidentAuthListener {
+    /**
+     * The user approved the incident or bug report to be sent.
+     */
+    void onReportApproved();
+
+    /**
+     * The user did not approve the incident or bug report to be sent.
+     */
+    void onReportDenied();
+}
diff --git a/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
new file mode 100644
index 0000000..98c2814
--- /dev/null
+++ b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.IIncidentAuthListener;
+import android.os.IncidentManager;
+
+/**
+ * Helper service for incidentd and dumpstated to provide user feedback
+ * and authorization for bug and inicdent reports to be taken.
+ *
+ * @hide
+ */
+interface IIncidentCompanion {
+    /**
+     * Request an authorization for an incident or bug report.
+     * // TODO(b/111441001): Add the permission
+     * <p>
+     * This function requires the ___ permission.
+     *
+     * @param callingUid The original application that requested the report.  This function
+     *      returns via the callback whether the application should be trusted.  It is up
+     *      to the caller to actually implement the restriction to take or not take
+     *      the incident or bug report.
+     * @param receiverClass The class that will be the eventual broacast receiver for the
+     *      INCIDENT_REPORT_READY message. Used as part of the id in incidentd.
+     * @param reportId The incident report ID.  Incidentd should call with this parameter, but
+     *     everyone else should pass null or empty string.
+     * @param flags FLAG_CONFIRMATION_DIALOG (0x1) - to show this as a dialog.  Otherwise
+     *      a dialog will be shown as a notification.
+     * @param callback Interface to receive results.  The results may not come back for
+     *      a long (user's choice) time, or ever (if they never respond to the notification).
+     *      Authorization requests are not persisted across reboot.  It is up to the calling
+     *      service to request another authorization after reboot if they still would like
+     *      to send their report.
+     */
+    oneway void authorizeReport(int callingUid, String callingPackage,
+            String receiverClass, String reportId,
+            int flags, IIncidentAuthListener callback);
+
+    /**
+     * Cancel an authorization.
+     */
+    oneway void cancelAuthorization(IIncidentAuthListener callback);
+
+    /**
+     * Send the report ready broadcast on behalf of incidentd.
+     */
+    oneway void sendReportReadyBroadcast(String pkg, String cls);
+
+    /**
+     * Return the list of pending approvals.
+     */
+    List<String> getPendingReports();
+
+    /**
+     * The user has authorized the report to be shared.
+     *
+     * @param uri the report.
+     */
+    void approveReport(String uri);
+
+    /**
+     * The user has denied the report from being shared.
+     *
+     * @param uri the report.
+     */
+    void denyReport(String uri);
+
+    /**
+     * List the incident reports for the given ComponentName.  The receiver
+     * must be for a package inside the caller.
+     */
+    List<String> getIncidentReportList(String pkg, String cls);
+
+    /**
+     * Get the IncidentReport object.
+     */
+    IncidentManager.IncidentReport getIncidentReport(String pkg, String cls, String id);
+
+    /**
+     * Signal that the client is done with this incident report and it can be deleted.
+     */
+    void deleteIncidentReports(String pkg, String cls, String id);
+
+    /**
+     * Signal that the client is done with all incident reports from this package.
+     * Especially useful for testing.
+     */
+    void deleteAllIncidentReports(String pkg);
+}
diff --git a/libs/incidentcompanion/binder/android/os/IncidentManager.aidl b/libs/incidentcompanion/binder/android/os/IncidentManager.aidl
new file mode 100644
index 0000000..d17823e
--- /dev/null
+++ b/libs/incidentcompanion/binder/android/os/IncidentManager.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package android.os;
+
+parcelable IncidentManager.IncidentReport cpp_header "android/os/IncidentManager.h";
+
diff --git a/libs/incidentcompanion/include/android/os/IncidentManager.h b/libs/incidentcompanion/include/android/os/IncidentManager.h
new file mode 100644
index 0000000..07b6d82
--- /dev/null
+++ b/libs/incidentcompanion/include/android/os/IncidentManager.h
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <utils/String16.h>
+
+#include <set>
+#include <vector>
+
+namespace android {
+namespace os {
+
+class IncidentManager : public virtual RefBase {
+public:
+    class IncidentReport : public Parcelable {
+    public:
+        IncidentReport();
+        virtual ~IncidentReport();
+
+        virtual status_t writeToParcel(Parcel* out) const;
+        virtual status_t readFromParcel(const Parcel* in);
+
+        void setTimestampNs(int64_t val) { mTimestampNs = val; }
+        int64_t getTimestampNs() const { return mTimestampNs; }
+        int64_t getTimestampMs() const { return mTimestampNs / 1000000; }
+
+        void setPrivacyPolicy(int32_t val) { mPrivacyPolicy = val; }
+        // This was accidentally published as a long in the java api.
+        int64_t getPrivacyPolicy() const { return mPrivacyPolicy; }
+        // Dups the fd, so you retain ownership of the original one.  If there is a
+        // previously set fd, closes that, since this object owns its own fd.
+        status_t setFileDescriptor(int fd);
+
+        // Does not dup the fd, so ownership is passed to this object.  If there is a
+        // previously set fd, closes that, since this object owns its own fd.
+        void takeFileDescriptor(int fd);
+
+        // Returns the fd, which you don't own.  Call dup if you need a copy.
+        int getFileDescriptor() const { return mFileDescriptor; }
+
+    private:
+        int64_t mTimestampNs;
+        int32_t mPrivacyPolicy;
+        int mFileDescriptor;
+    };
+
+
+private:
+    // Not implemented for now.
+    IncidentManager();
+    virtual ~IncidentManager();
+};
+}
+}
+
diff --git a/libs/incidentcompanion/src/IncidentManager.cpp b/libs/incidentcompanion/src/IncidentManager.cpp
new file mode 100644
index 0000000..f7c8a5e
--- /dev/null
+++ b/libs/incidentcompanion/src/IncidentManager.cpp
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/os/IncidentManager.h>
+
+namespace android {
+namespace os {
+
+// ============================================================
+IncidentManager::IncidentReport::IncidentReport()
+        :mTimestampNs(0),
+         mPrivacyPolicy(0),
+         mFileDescriptor(-1) {
+}
+
+IncidentManager::IncidentReport::~IncidentReport() {
+    if (mFileDescriptor >= 0) {
+        close(mFileDescriptor);
+    }
+}
+
+status_t IncidentManager::IncidentReport::writeToParcel(Parcel* out) const {
+    status_t err;
+
+    err = out->writeInt64(mTimestampNs);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+
+    err = out->writeInt32(mPrivacyPolicy);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (mFileDescriptor >= 0) {
+        err = out->writeInt32(1);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+        err = out->writeDupParcelFileDescriptor(mFileDescriptor);
+        if (err != NO_ERROR) {
+            return err;
+        }
+
+    } else {
+        err = out->writeInt32(0);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t IncidentManager::IncidentReport::readFromParcel(const Parcel* in) {
+    status_t err;
+    int32_t hasField;
+
+    err = in->readInt64(&mTimestampNs);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = in->readInt32(&mPrivacyPolicy);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    err = in->readInt32(&hasField);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (hasField) {
+        int fd = in->readParcelFileDescriptor();
+        if (fd >= 0) {
+            mFileDescriptor = dup(fd);
+            if (mFileDescriptor < 0) {
+                return -errno;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t IncidentManager::IncidentReport::setFileDescriptor(int fd) {
+    if (mFileDescriptor >= 0) {
+        close(mFileDescriptor);
+    }
+    if (fd < 0) {
+        mFileDescriptor = -1;
+    } else {
+        mFileDescriptor = dup(fd);
+        if (mFileDescriptor < 0) {
+            return -errno;
+        }
+    }
+    return NO_ERROR;
+}
+
+void IncidentManager::IncidentReport::takeFileDescriptor(int fd) {
+    if (mFileDescriptor >= 0) {
+        close(mFileDescriptor);
+    }
+    if (fd < 0) {
+        mFileDescriptor = -1;
+    } else {
+        mFileDescriptor = fd;
+    }
+}
+
+// ============================================================
+IncidentManager::~IncidentManager() {
+}
+
+}
+}
+
+
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 2f39976..2d78811 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -28,6 +28,7 @@
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
+        "TouchVideoFrame.cpp",
         "VirtualKeyMap.cpp",
     ],
 
@@ -43,7 +44,10 @@
         android: {
             srcs: [
                 "IInputFlinger.cpp",
+                "InputApplication.cpp",
                 "InputTransport.cpp",
+                "InputWindow.cpp",
+                "ISetInputWindowsListener.cpp",
                 "VelocityControl.cpp",
                 "VelocityTracker.cpp",
             ],
@@ -51,6 +55,7 @@
             shared_libs: [
                 "libutils",
                 "libbinder",
+                "libui"
             ],
 
             sanitize: {
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 003e73d..d6a73bf 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -23,7 +23,6 @@
 
 #include <input/IInputFlinger.h>
 
-
 namespace android {
 
 class BpInputFlinger : public BpInterface<IInputFlinger> {
@@ -31,23 +30,85 @@
     explicit BpInputFlinger(const sp<IBinder>& impl) :
             BpInterface<IInputFlinger>(impl) { }
 
-    virtual status_t doSomething() {
+    virtual void setInputWindows(const std::vector<InputWindowInfo>& inputInfo,
+            const sp<ISetInputWindowsListener>& setInputWindowsListener) {
         Parcel data, reply;
         data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
-        remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply);
-        return reply.readInt32();
+
+        data.writeUint32(static_cast<uint32_t>(inputInfo.size()));
+        for (const auto& info : inputInfo) {
+            info.write(data);
+        }
+        data.writeStrongBinder(IInterface::asBinder(setInputWindowsListener));
+
+        remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+
+        data.writeStrongBinder(fromToken);
+        data.writeStrongBinder(toToken);
+        remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void registerInputChannel(const sp<InputChannel>& channel) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+        channel->write(data);
+        remote()->transact(BnInputFlinger::REGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
+    }
+
+    virtual void unregisterInputChannel(const sp<InputChannel>& channel) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+        channel->write(data);
+        remote()->transact(BnInputFlinger::UNREGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
     }
 };
 
 IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
 
-
 status_t BnInputFlinger::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
     switch(code) {
-    case DO_SOMETHING_TRANSACTION: {
+    case SET_INPUT_WINDOWS_TRANSACTION: {
         CHECK_INTERFACE(IInputFlinger, data, reply);
-        reply->writeInt32(0);
+        size_t count = data.readUint32();
+        if (count > data.dataSize()) {
+            return BAD_VALUE;
+        }
+        std::vector<InputWindowInfo> handles;
+        for (size_t i = 0; i < count; i++) {
+            handles.push_back(InputWindowInfo::read(data));
+        }
+        const sp<ISetInputWindowsListener> setInputWindowsListener =
+                ISetInputWindowsListener::asInterface(data.readStrongBinder());
+        setInputWindows(handles, setInputWindowsListener);
+        break;
+    }
+    case REGISTER_INPUT_CHANNEL_TRANSACTION: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        sp<InputChannel> channel = new InputChannel();
+        channel->read(data);
+        registerInputChannel(channel);
+        break;
+    }
+    case UNREGISTER_INPUT_CHANNEL_TRANSACTION: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        sp<InputChannel> channel = new InputChannel();
+        channel->read(data);
+        unregisterInputChannel(channel);
+        break;
+    }
+    case TRANSFER_TOUCH_FOCUS: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        sp<IBinder> fromToken = data.readStrongBinder();
+        sp<IBinder> toToken = data.readStrongBinder();
+        transferTouchFocus(fromToken, toToken);
         break;
     }
     default:
diff --git a/libs/input/ISetInputWindowsListener.cpp b/libs/input/ISetInputWindowsListener.cpp
new file mode 100644
index 0000000..a0330da
--- /dev/null
+++ b/libs/input/ISetInputWindowsListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/ISetInputWindowsListener.h>
+
+namespace android {
+
+class BpSetInputWindowsListener : public BpInterface<ISetInputWindowsListener> {
+public:
+    explicit BpSetInputWindowsListener(const sp<IBinder>& impl)
+        : BpInterface<ISetInputWindowsListener>(impl) {
+    }
+
+    virtual ~BpSetInputWindowsListener() = default;
+
+    virtual void onSetInputWindowsFinished() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISetInputWindowsListener::getInterfaceDescriptor());
+        remote()->transact(BnSetInputWindowsListener::ON_SET_INPUT_WINDOWS_FINISHED, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(SetInputWindowsListener, "android.input.ISetInputWindowsListener");
+
+status_t BnSetInputWindowsListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    switch(code) {
+        case ON_SET_INPUT_WINDOWS_FINISHED: {
+            CHECK_INTERFACE(ISetInputWindowsListener, data, reply);
+            onSetInputWindowsFinished();
+            return NO_ERROR;
+        }
+        default: {
+            return BBinder::onTransact(code, data, reply, flags);
+        }
+    }
+}
+
+} // namespace android
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a624663..9fd25f9 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -29,16 +29,29 @@
 
 namespace android {
 
+const char* motionClassificationToString(MotionClassification classification) {
+    switch (classification) {
+        case MotionClassification::NONE:
+            return "NONE";
+        case MotionClassification::AMBIGUOUS_GESTURE:
+            return "AMBIGUOUS_GESTURE";
+        case MotionClassification::DEEP_PRESS:
+            return "DEEP_PRESS";
+    }
+}
+
 // --- InputEvent ---
 
-void InputEvent::initialize(int32_t deviceId, int32_t source) {
+void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId) {
     mDeviceId = deviceId;
     mSource = source;
+    mDisplayId = displayId;
 }
 
 void InputEvent::initialize(const InputEvent& from) {
     mDeviceId = from.mDeviceId;
     mSource = from.mSource;
+    mDisplayId = from.mDisplayId;
 }
 
 // --- KeyEvent ---
@@ -54,6 +67,7 @@
 void KeyEvent::initialize(
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t flags,
         int32_t keyCode,
@@ -62,7 +76,7 @@
         int32_t repeatCount,
         nsecs_t downTime,
         nsecs_t eventTime) {
-    InputEvent::initialize(deviceId, source);
+    InputEvent::initialize(deviceId, source, displayId);
     mAction = action;
     mFlags = flags;
     mKeyCode = keyCode;
@@ -128,15 +142,24 @@
     }
 }
 
-void PointerCoords::scale(float scaleFactor) {
+void PointerCoords::scale(float globalScaleFactor, float windowXScale, float windowYScale) {
     // No need to scale pressure or size since they are normalized.
     // No need to scale orientation since it is meaningless to do so.
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
-    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+
+    // If there is a global scale factor, it is included in the windowX/YScale
+    // so we don't need to apply it twice to the X/Y axes.
+    // However we don't want to apply any windowXYScale not included in the global scale
+    // to the TOUCH_MAJOR/MINOR coordinates.
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, windowXScale);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, windowYScale);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, globalScaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
+}
+
+void PointerCoords::scale(float globalScaleFactor) {
+    scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
 }
 
 void PointerCoords::applyOffset(float xOffset, float yOffset) {
@@ -215,12 +238,14 @@
 void MotionEvent::initialize(
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t actionButton,
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
         int32_t buttonState,
+        MotionClassification classification,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -230,13 +255,14 @@
         size_t pointerCount,
         const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
-    InputEvent::initialize(deviceId, source);
+    InputEvent::initialize(deviceId, source, displayId);
     mAction = action;
     mActionButton = actionButton;
     mFlags = flags;
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
     mButtonState = buttonState;
+    mClassification = classification;
     mXOffset = xOffset;
     mYOffset = yOffset;
     mXPrecision = xPrecision;
@@ -250,13 +276,14 @@
 }
 
 void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
-    InputEvent::initialize(other->mDeviceId, other->mSource);
+    InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId);
     mAction = other->mAction;
     mActionButton = other->mActionButton;
     mFlags = other->mFlags;
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
     mButtonState = other->mButtonState;
+    mClassification = other->mClassification;
     mXOffset = other->mXOffset;
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
@@ -341,15 +368,15 @@
     mYOffset += yOffset;
 }
 
-void MotionEvent::scale(float scaleFactor) {
-    mXOffset *= scaleFactor;
-    mYOffset *= scaleFactor;
-    mXPrecision *= scaleFactor;
-    mYPrecision *= scaleFactor;
+void MotionEvent::scale(float globalScaleFactor) {
+    mXOffset *= globalScaleFactor;
+    mYOffset *= globalScaleFactor;
+    mXPrecision *= globalScaleFactor;
+    mYPrecision *= globalScaleFactor;
 
     size_t numSamples = mSamplePointerCoords.size();
     for (size_t i = 0; i < numSamples; i++) {
-        mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
+        mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor);
     }
 }
 
@@ -431,12 +458,14 @@
 
     mDeviceId = parcel->readInt32();
     mSource = parcel->readInt32();
+    mDisplayId = parcel->readInt32();
     mAction = parcel->readInt32();
     mActionButton = parcel->readInt32();
     mFlags = parcel->readInt32();
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
     mButtonState = parcel->readInt32();
+    mClassification = static_cast<MotionClassification>(parcel->readByte());
     mXOffset = parcel->readFloat();
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
@@ -480,12 +509,14 @@
 
     parcel->writeInt32(mDeviceId);
     parcel->writeInt32(mSource);
+    parcel->writeInt32(mDisplayId);
     parcel->writeInt32(mAction);
     parcel->writeInt32(mActionButton);
     parcel->writeInt32(mFlags);
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
     parcel->writeInt32(mButtonState);
+    parcel->writeByte(static_cast<int8_t>(mClassification));
     parcel->writeFloat(mXOffset);
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
new file mode 100644
index 0000000..1d9f8a7
--- /dev/null
+++ b/libs/input/InputApplication.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 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 "InputApplication"
+
+#include <input/InputApplication.h>
+
+#include <android/log.h>
+
+namespace android {
+
+// --- InputApplicationHandle ---
+
+InputApplicationHandle::InputApplicationHandle() {
+}
+
+InputApplicationHandle::~InputApplicationHandle() {
+}
+
+InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
+    InputApplicationInfo ret;
+    ret.token = from.readStrongBinder();
+    ret.name = from.readString8().c_str();
+    ret.dispatchingTimeout = from.readInt64();
+
+    return ret;
+}
+
+status_t InputApplicationInfo::write(Parcel& output) const {
+    output.writeStrongBinder(token);
+    output.writeString8(String8(name.c_str()));
+    output.writeInt64(dispatchingTimeout);
+    
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 4287abe..4db9e06 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -20,9 +20,12 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <android-base/stringprintf.h>
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
 
+using android::base::StringPrintf;
+
 namespace android {
 
 static const char* CONFIGURATION_FILE_DIR[] = {
@@ -41,65 +44,62 @@
     return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_');
 }
 
-static void appendInputDeviceConfigurationFileRelativePath(String8& path,
-        const String8& name, InputDeviceConfigurationFileType type) {
-    path.append(CONFIGURATION_FILE_DIR[type]);
-    for (size_t i = 0; i < name.length(); i++) {
-        char ch = name[i];
-        if (!isValidNameChar(ch)) {
-            ch = '_';
-        }
-        path.append(&ch, 1);
-    }
-    path.append(CONFIGURATION_FILE_EXTENSION[type]);
+static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
+        const std::string& name, InputDeviceConfigurationFileType type) {
+    path += CONFIGURATION_FILE_DIR[type];
+    path += name;
+    path += CONFIGURATION_FILE_EXTENSION[type];
 }
 
-String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
+std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
         const InputDeviceIdentifier& deviceIdentifier,
         InputDeviceConfigurationFileType type) {
     if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
         if (deviceIdentifier.version != 0) {
             // Try vendor product version.
-            String8 versionPath(getInputDeviceConfigurationFilePathByName(
-                    String8::format("Vendor_%04x_Product_%04x_Version_%04x",
+            std::string versionPath = getInputDeviceConfigurationFilePathByName(
+                    StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
                             deviceIdentifier.vendor, deviceIdentifier.product,
                             deviceIdentifier.version),
-                    type));
-            if (!versionPath.isEmpty()) {
+                    type);
+            if (!versionPath.empty()) {
                 return versionPath;
             }
         }
 
         // Try vendor product.
-        String8 productPath(getInputDeviceConfigurationFilePathByName(
-                String8::format("Vendor_%04x_Product_%04x",
+        std::string productPath = getInputDeviceConfigurationFilePathByName(
+                StringPrintf("Vendor_%04x_Product_%04x",
                         deviceIdentifier.vendor, deviceIdentifier.product),
-                type));
-        if (!productPath.isEmpty()) {
+                type);
+        if (!productPath.empty()) {
             return productPath;
         }
     }
 
     // Try device name.
-    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
+    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
 }
 
-String8 getInputDeviceConfigurationFilePathByName(
-        const String8& name, InputDeviceConfigurationFileType type) {
+std::string getInputDeviceConfigurationFilePathByName(
+        const std::string& name, InputDeviceConfigurationFileType type) {
     // Search system repository.
-    String8 path;
+    std::string path;
 
     // Treblized input device config files will be located /odm/usr or /vendor/usr.
     const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
     for (size_t i = 0; i < size(rootsForPartition); i++) {
-        path.setTo(rootsForPartition[i]);
-        path.append("/usr/");
+        if (rootsForPartition[i] == nullptr) {
+            continue;
+        }
+        path = rootsForPartition[i];
+        path += "/usr/";
         appendInputDeviceConfigurationFileRelativePath(path, name, type);
 #if DEBUG_PROBE
         ALOGD("Probing for system provided input device configuration file: path='%s'",
-              path.string());
+              path.c_str());
 #endif
-        if (!access(path.string(), R_OK)) {
+        if (!access(path.c_str(), R_OK)) {
 #if DEBUG_PROBE
             ALOGD("Found");
 #endif
@@ -109,13 +109,17 @@
 
     // Search user repository.
     // TODO Should only look here if not in safe mode.
-    path.setTo(getenv("ANDROID_DATA"));
-    path.append("/system/devices/");
+    path = "";
+    char *androidData = getenv("ANDROID_DATA");
+    if (androidData != nullptr) {
+        path += androidData;
+    }
+    path += "/system/devices/";
     appendInputDeviceConfigurationFileRelativePath(path, name, type);
 #if DEBUG_PROBE
-    ALOGD("Probing for system user input device configuration file: path='%s'", path.string());
+    ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
 #endif
-    if (!access(path.string(), R_OK)) {
+    if (!access(path.c_str(), R_OK)) {
 #if DEBUG_PROBE
         ALOGD("Found");
 #endif
@@ -125,16 +129,28 @@
     // Not found.
 #if DEBUG_PROBE
     ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
-            name.string(), type);
+            name.c_str(), type);
 #endif
-    return String8();
+    return "";
+}
+
+// --- InputDeviceIdentifier
+
+std::string InputDeviceIdentifier::getCanonicalName() const {
+    std::string replacedName = name;
+    for (char& ch : replacedName) {
+        if (!isValidNameChar(ch)) {
+            ch = '_';
+        }
+    }
+    return replacedName;
 }
 
 
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
-    initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
+    initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
 }
 
 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
@@ -150,7 +166,7 @@
 }
 
 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
-        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+        const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
         bool hasMic) {
     mId = id;
     mGeneration = generation;
@@ -170,12 +186,12 @@
         int32_t axis, uint32_t source) const {
     size_t numRanges = mMotionRanges.size();
     for (size_t i = 0; i < numRanges; i++) {
-        const MotionRange& range = mMotionRanges.itemAt(i);
+        const MotionRange& range = mMotionRanges[i];
         if (range.axis == axis && range.source == source) {
             return &range;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 void InputDeviceInfo::addSource(uint32_t source) {
@@ -185,11 +201,11 @@
 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
         float flat, float fuzz, float resolution) {
     MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
-    mMotionRanges.add(range);
+    mMotionRanges.push_back(range);
 }
 
 void InputDeviceInfo::addMotionRange(const MotionRange& range) {
-    mMotionRanges.add(range);
+    mMotionRanges.push_back(range);
 }
 
 } // namespace android
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 03f593f..d02cb8e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -27,11 +27,16 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
 #include <cutils/properties.h>
 #include <log/log.h>
+#include <utils/Trace.h>
 
 #include <input/InputTransport.h>
 
+using android::base::StringPrintf;
+
 namespace android {
 
 // Socket buffer size.  The default is typically about 128KB, which is much larger than
@@ -58,6 +63,18 @@
 // far into the future.  This time is further bounded by 50% of the last time delta.
 static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
 
+/**
+ * System property for enabling / disabling touch resampling.
+ * Resampling extrapolates / interpolates the reported touch event coordinates to better
+ * align them to the VSYNC signal, thus resulting in smoother scrolling performance.
+ * Resampling is not needed (and should be disabled) on hardware that already
+ * has touch events triggered by VSYNC.
+ * Set to "1" to enable resampling (default).
+ * Set to "0" to disable resampling.
+ * Resampling is enabled by default.
+ */
+static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
+
 template<typename T>
 inline static T min(const T& a, const T& b) {
     return a < b ? a : b;
@@ -67,6 +84,10 @@
     return a + alpha * (b - a);
 }
 
+inline static bool isPointerEvent(int32_t source) {
+    return (source & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
+}
+
 // --- InputMessage ---
 
 bool InputMessage::isValid(size_t actualSize) const {
@@ -156,6 +177,8 @@
             msg->body.motion.metaState = body.motion.metaState;
             // int32_t buttonState
             msg->body.motion.buttonState = body.motion.buttonState;
+            // MotionClassification classification
+            msg->body.motion.classification = body.motion.classification;
             // int32_t edgeFlags
             msg->body.motion.edgeFlags = body.motion.edgeFlags;
             // nsecs_t downTime
@@ -200,15 +223,13 @@
 // --- InputChannel ---
 
 InputChannel::InputChannel(const std::string& name, int fd) :
-        mName(name), mFd(fd) {
+        mName(name) {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel constructed: name='%s', fd=%d",
             mName.c_str(), fd);
 #endif
 
-    int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
-            "non-blocking.  errno=%d", mName.c_str(), errno);
+    setFd(fd);
 }
 
 InputChannel::~InputChannel() {
@@ -220,6 +241,18 @@
     ::close(mFd);
 }
 
+void InputChannel::setFd(int fd) {
+    if (mFd > 0) {
+        ::close(mFd);
+    }
+    mFd = fd;
+    if (mFd > 0) {
+        int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
+        LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
+            "non-blocking.  errno=%d", mName.c_str(), errno);
+    }
+}
+
 status_t InputChannel::openInputChannelPair(const std::string& name,
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
     int sockets[2];
@@ -328,10 +361,51 @@
 
 sp<InputChannel> InputChannel::dup() const {
     int fd = ::dup(getFd());
-    return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
+    return fd >= 0 ? new InputChannel(getName(), fd) : nullptr;
 }
 
 
+status_t InputChannel::write(Parcel& out) const {
+    status_t s = out.writeString8(String8(getName().c_str()));
+
+    if (s != OK) {
+        return s;
+    }
+    s = out.writeStrongBinder(mToken);
+    if (s != OK) {
+        return s;
+    }
+
+    s = out.writeDupFileDescriptor(getFd());
+
+    return s;
+}
+
+status_t InputChannel::read(const Parcel& from) {
+    mName = from.readString8();
+    mToken = from.readStrongBinder();
+
+    int rawFd = from.readFileDescriptor();
+    setFd(::dup(rawFd));
+
+    if (mFd < 0) {
+        return BAD_VALUE;
+    }
+
+    return OK;
+}
+
+sp<IBinder> InputChannel::getToken() const {
+    return mToken;
+}
+
+void InputChannel::setToken(const sp<IBinder>& token) {
+    if (mToken != nullptr) {
+        ALOGE("Assigning InputChannel (%s) a second handle?", mName.c_str());
+    }
+    mToken = token;
+}
+
 // --- InputPublisher ---
 
 InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
@@ -345,6 +419,7 @@
         uint32_t seq,
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t flags,
         int32_t keyCode,
@@ -353,6 +428,11 @@
         int32_t repeatCount,
         nsecs_t downTime,
         nsecs_t eventTime) {
+    if (ATRACE_ENABLED()) {
+        std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
+                mChannel->getName().c_str(), keyCode);
+        ATRACE_NAME(message.c_str());
+    }
 #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,"
@@ -372,6 +452,7 @@
     msg.body.key.seq = seq;
     msg.body.key.deviceId = deviceId;
     msg.body.key.source = source;
+    msg.body.key.displayId = displayId;
     msg.body.key.action = action;
     msg.body.key.flags = flags;
     msg.body.key.keyCode = keyCode;
@@ -394,6 +475,7 @@
         int32_t edgeFlags,
         int32_t metaState,
         int32_t buttonState,
+        MotionClassification classification,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -403,14 +485,22 @@
         uint32_t pointerCount,
         const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
+    if (ATRACE_ENABLED()) {
+        std::string message = StringPrintf(
+                "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
+                mChannel->getName().c_str(), action);
+        ATRACE_NAME(message.c_str());
+    }
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
+            "displayId=%" PRId32 ", "
             "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
-            "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
+            "metaState=0x%x, buttonState=0x%x, classification=%s, xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
             "pointerCount=%" PRIu32,
             mChannel->getName().c_str(), seq,
-            deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
+            deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,
+            buttonState, motionClassificationToString(classification),
             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
 
@@ -437,6 +527,7 @@
     msg.body.motion.edgeFlags = edgeFlags;
     msg.body.motion.metaState = metaState;
     msg.body.motion.buttonState = buttonState;
+    msg.body.motion.classification = classification;
     msg.body.motion.xOffset = xOffset;
     msg.body.motion.yOffset = yOffset;
     msg.body.motion.xPrecision = xPrecision;
@@ -485,31 +576,18 @@
 }
 
 bool InputConsumer::isTouchResamplingEnabled() {
-    char value[PROPERTY_VALUE_MAX];
-    int length = property_get("ro.input.noresample", value, NULL);
-    if (length > 0) {
-        if (!strcmp("1", value)) {
-            return false;
-        }
-        if (strcmp("0", value)) {
-            ALOGD("Unrecognized property value for 'ro.input.noresample'.  "
-                    "Use '1' or '0'.");
-        }
-    }
-    return true;
+    return property_get_bool(PROPERTY_RESAMPLING_ENABLED, true);
 }
 
 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
-        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
-        int32_t* displayId) {
+        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
             mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
 #endif
 
     *outSeq = 0;
-    *outEvent = NULL;
-    *displayId = -1;  // Invalid display.
+    *outEvent = nullptr;
 
     // Fetch the next input message.
     // Loop until an event can be returned or no additional events are received.
@@ -524,7 +602,7 @@
             if (result) {
                 // Consume the next batched event unless batches are being held for later.
                 if (consumeBatches || result != WOULD_BLOCK) {
-                    result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
+                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -563,12 +641,22 @@
                             mChannel->getName().c_str());
 #endif
                     break;
+                } else if (isPointerEvent(mMsg.body.motion.source) &&
+                        mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
+                    // No need to process events that we are going to cancel anyways
+                    const size_t count = batch.samples.size();
+                    for (size_t i = 0; i < count; i++) {
+                        const InputMessage& msg = batch.samples.itemAt(i);
+                        sendFinishedSignal(msg.body.motion.seq, false);
+                    }
+                    batch.samples.removeItemsAt(0, count);
+                    mBatches.removeAt(batchIndex);
                 } else {
                     // We cannot append to the batch in progress, so we need to consume
                     // the previous batch right now and defer the new message until later.
                     mMsgDeferred = true;
                     status_t result = consumeSamples(factory,
-                            batch, batch.samples.size(), outSeq, outEvent, displayId);
+                            batch, batch.samples.size(), outSeq, outEvent);
                     mBatches.removeAt(batchIndex);
                     if (result) {
                         return result;
@@ -602,7 +690,7 @@
             initializeMotionEvent(motionEvent, &mMsg);
             *outSeq = mMsg.body.motion.seq;
             *outEvent = motionEvent;
-            *displayId = mMsg.body.motion.displayId;
+
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
                     mChannel->getName().c_str(), *outSeq);
@@ -620,14 +708,13 @@
 }
 
 status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
-        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
+        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
     status_t result;
     for (size_t i = mBatches.size(); i > 0; ) {
         i--;
         Batch& batch = mBatches.editItemAt(i);
         if (frameTime < 0) {
-            result = consumeSamples(factory, batch, batch.samples.size(),
-                    outSeq, outEvent, displayId);
+            result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent);
             mBatches.removeAt(i);
             return result;
         }
@@ -641,11 +728,11 @@
             continue;
         }
 
-        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
+        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
         const InputMessage* next;
         if (batch.samples.isEmpty()) {
             mBatches.removeAt(i);
-            next = NULL;
+            next = nullptr;
         } else {
             next = &batch.samples.itemAt(0);
         }
@@ -659,7 +746,7 @@
 }
 
 status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
-        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
+        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
     MotionEvent* motionEvent = factory->createMotionEvent();
     if (! motionEvent) return NO_MEMORY;
 
@@ -674,7 +761,6 @@
             mSeqChains.push(seqChain);
             addSample(motionEvent, &msg);
         } else {
-            *displayId = msg.body.motion.displayId;
             initializeMotionEvent(motionEvent, &msg);
         }
         chain = msg.body.motion.seq;
@@ -687,8 +773,7 @@
 }
 
 void InputConsumer::updateTouchState(InputMessage& msg) {
-    if (!mResampleTouch ||
-            !(msg.body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
+    if (!mResampleTouch || !isPointerEvent(msg.body.motion.source)) {
         return;
     }
 
@@ -800,7 +885,7 @@
 void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event,
     const InputMessage* next) {
     if (!mResampleTouch
-            || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)
+            || !(isPointerEvent(event->getSource()))
             || event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
         return;
     }
@@ -1030,6 +1115,7 @@
     event->initialize(
             msg->body.key.deviceId,
             msg->body.key.source,
+            msg->body.key.displayId,
             msg->body.key.action,
             msg->body.key.flags,
             msg->body.key.keyCode,
@@ -1052,12 +1138,14 @@
     event->initialize(
             msg->body.motion.deviceId,
             msg->body.motion.source,
+            msg->body.motion.displayId,
             msg->body.motion.action,
             msg->body.motion.actionButton,
             msg->body.motion.flags,
             msg->body.motion.edgeFlags,
             msg->body.motion.metaState,
             msg->body.motion.buttonState,
+            msg->body.motion.classification,
             msg->body.motion.xOffset,
             msg->body.motion.yOffset,
             msg->body.motion.xPrecision,
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
new file mode 100644
index 0000000..5a60347
--- /dev/null
+++ b/libs/input/InputWindow.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 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 "InputWindow"
+#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+#include <input/InputWindow.h>
+#include <input/InputTransport.h>
+
+#include <log/log.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+
+// --- InputWindowInfo ---
+void InputWindowInfo::addTouchableRegion(const Rect& region) {
+    touchableRegion.orSelf(region);
+}
+
+bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+    return touchableRegion.contains(x,y);
+}
+
+bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
+    return x >= frameLeft && x < frameRight
+            && y >= frameTop && y < frameBottom;
+}
+
+bool InputWindowInfo::isTrustedOverlay() const {
+    return layoutParamsType == TYPE_INPUT_METHOD
+            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
+            || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
+            || layoutParamsType == TYPE_STATUS_BAR
+            || layoutParamsType == TYPE_NAVIGATION_BAR
+            || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
+            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
+            || layoutParamsType == TYPE_DOCK_DIVIDER
+            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+            || layoutParamsType == TYPE_INPUT_CONSUMER;
+}
+
+bool InputWindowInfo::supportsSplitTouch() const {
+    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
+}
+
+bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
+    return frameLeft < other->frameRight && frameRight > other->frameLeft
+            && frameTop < other->frameBottom && frameBottom > other->frameTop;
+}
+
+status_t InputWindowInfo::write(Parcel& output) const {
+    if (token == nullptr) {
+        output.writeInt32(0);
+        return OK;
+    }
+    output.writeInt32(1);
+    status_t s = output.writeStrongBinder(token);
+    if (s != OK) return s;
+
+    output.writeString8(String8(name.c_str()));
+    output.writeInt32(layoutParamsFlags);
+    output.writeInt32(layoutParamsType);
+    output.writeInt64(dispatchingTimeout);
+    output.writeInt32(frameLeft);
+    output.writeInt32(frameTop);
+    output.writeInt32(frameRight);
+    output.writeInt32(frameBottom);
+    output.writeInt32(surfaceInset);
+    output.writeFloat(globalScaleFactor);
+    output.writeFloat(windowXScale);
+    output.writeFloat(windowYScale);
+    output.writeBool(visible);
+    output.writeBool(canReceiveKeys);
+    output.writeBool(hasFocus);
+    output.writeBool(hasWallpaper);
+    output.writeBool(paused);
+    output.writeInt32(layer);
+    output.writeInt32(ownerPid);
+    output.writeInt32(ownerUid);
+    output.writeInt32(inputFeatures);
+    output.writeInt32(displayId);
+    output.writeInt32(portalToDisplayId);
+    applicationInfo.write(output);
+    output.write(touchableRegion);
+    output.writeBool(replaceTouchableRegionWithCrop);
+    output.writeWeakBinder(touchableRegionCropHandle);
+    return OK;
+}
+
+InputWindowInfo InputWindowInfo::read(const Parcel& from) {
+    InputWindowInfo ret;
+
+    if (from.readInt32() == 0) {
+        return ret;
+    }
+
+    sp<IBinder> token = from.readStrongBinder();
+    if (token == nullptr) {
+        return ret;
+    }
+
+    ret.token = token;
+    ret.name = from.readString8().c_str();
+    ret.layoutParamsFlags = from.readInt32();
+    ret.layoutParamsType = from.readInt32();
+    ret.dispatchingTimeout = from.readInt64();
+    ret.frameLeft = from.readInt32();
+    ret.frameTop = from.readInt32();
+    ret.frameRight = from.readInt32();
+    ret.frameBottom = from.readInt32();
+    ret.surfaceInset = from.readInt32();
+    ret.globalScaleFactor = from.readFloat();
+    ret.windowXScale = from.readFloat();
+    ret.windowYScale = from.readFloat();
+    ret.visible = from.readBool();
+    ret.canReceiveKeys = from.readBool();
+    ret.hasFocus = from.readBool();
+    ret.hasWallpaper = from.readBool();
+    ret.paused = from.readBool();
+    ret.layer = from.readInt32();
+    ret.ownerPid = from.readInt32();
+    ret.ownerUid = from.readInt32();
+    ret.inputFeatures = from.readInt32();
+    ret.displayId = from.readInt32();
+    ret.portalToDisplayId = from.readInt32();
+    ret.applicationInfo = InputApplicationInfo::read(from);
+    from.read(ret.touchableRegion);
+    ret.replaceTouchableRegionWithCrop = from.readBool();
+    ret.touchableRegionCropHandle = from.readWeakBinder();
+
+    return ret;
+}
+
+InputWindowInfo::InputWindowInfo(const Parcel& from) {
+    *this = read(from);
+}
+
+// --- InputWindowHandle ---
+
+InputWindowHandle::InputWindowHandle() {
+}
+
+InputWindowHandle::~InputWindowHandle() {
+}
+
+void InputWindowHandle::releaseChannel() {
+    mInfo.token.clear();
+}
+
+sp<IBinder> InputWindowHandle::getToken() const {
+    return mInfo.token;
+}
+
+void InputWindowHandle::updateFrom(sp<InputWindowHandle> handle) {
+    mInfo = handle->mInfo;
+}
+
+} // namespace android
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index cba1111..e189d20 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -106,14 +106,14 @@
     }
 }
 
-status_t KeyCharacterMap::load(const String8& filename,
+status_t KeyCharacterMap::load(const std::string& filename,
         Format format, sp<KeyCharacterMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
+    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
     if (status) {
-        ALOGE("Error %d opening key character map file %s.", status, filename.string());
+        ALOGE("Error %d opening key character map file %s.", status, filename.c_str());
     } else {
         status = load(tokenizer, format, outMap);
         delete tokenizer;
@@ -121,12 +121,12 @@
     return status;
 }
 
-status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
+status_t KeyCharacterMap::loadContents(const std::string& filename, const char* contents,
         Format format, sp<KeyCharacterMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
+    status_t status = Tokenizer::fromContents(String8(filename.c_str()), contents, &tokenizer);
     if (status) {
         ALOGE("Error %d opening key character map.", status);
     } else {
@@ -164,10 +164,10 @@
 
 sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
         const sp<KeyCharacterMap>& overlay) {
-    if (overlay == NULL) {
+    if (overlay == nullptr) {
         return base;
     }
-    if (base == NULL) {
+    if (base == nullptr) {
         return overlay;
     }
 
@@ -468,7 +468,7 @@
 
         // Try to find the most general behavior that maps to this character.
         // For example, the base key behavior will usually be last in the list.
-        const Behavior* found = NULL;
+        const Behavior* found = nullptr;
         for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
             if (behavior->character == ch) {
                 found = behavior;
@@ -487,7 +487,7 @@
         int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
     outEvents.push();
     KeyEvent& event = outEvents.editTop();
-    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
+    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
             0, keyCode, 0, metaState, 0, time, time);
 }
@@ -605,11 +605,11 @@
     map->mType = parcel->readInt32();
     size_t numKeys = parcel->readInt32();
     if (parcel->errorCheck()) {
-        return NULL;
+        return nullptr;
     }
     if (numKeys > MAX_KEYS) {
         ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
-        return NULL;
+        return nullptr;
     }
 
     for (size_t i = 0; i < numKeys; i++) {
@@ -617,7 +617,7 @@
         char16_t label = parcel->readInt32();
         char16_t number = parcel->readInt32();
         if (parcel->errorCheck()) {
-            return NULL;
+            return nullptr;
         }
 
         Key* key = new Key();
@@ -625,14 +625,14 @@
         key->number = number;
         map->mKeys.add(keyCode, key);
 
-        Behavior* lastBehavior = NULL;
+        Behavior* lastBehavior = nullptr;
         while (parcel->readInt32()) {
             int32_t metaState = parcel->readInt32();
             char16_t character = parcel->readInt32();
             int32_t fallbackKeyCode = parcel->readInt32();
             int32_t replacementKeyCode = parcel->readInt32();
             if (parcel->errorCheck()) {
-                return NULL;
+                return nullptr;
             }
 
             Behavior* behavior = new Behavior();
@@ -649,7 +649,7 @@
         }
 
         if (parcel->errorCheck()) {
-            return NULL;
+            return nullptr;
         }
     }
     return map;
@@ -666,7 +666,7 @@
         parcel->writeInt32(keyCode);
         parcel->writeInt32(key->label);
         parcel->writeInt32(key->number);
-        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
+        for (const Behavior* behavior = key->firstBehavior; behavior != nullptr;
                 behavior = behavior->next) {
             parcel->writeInt32(1);
             parcel->writeInt32(behavior->metaState);
@@ -683,12 +683,12 @@
 // --- KeyCharacterMap::Key ---
 
 KeyCharacterMap::Key::Key() :
-        label(0), number(0), firstBehavior(NULL) {
+        label(0), number(0), firstBehavior(nullptr) {
 }
 
 KeyCharacterMap::Key::Key(const Key& other) :
         label(other.label), number(other.number),
-        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
+        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : nullptr) {
 }
 
 KeyCharacterMap::Key::~Key() {
@@ -704,11 +704,11 @@
 // --- KeyCharacterMap::Behavior ---
 
 KeyCharacterMap::Behavior::Behavior() :
-        next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
+        next(nullptr), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
 }
 
 KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
-        next(other.next ? new Behavior(*other.next) : NULL),
+        next(other.next ? new Behavior(*other.next) : nullptr),
         metaState(other.metaState), character(other.character),
         fallbackKeyCode(other.fallbackKeyCode),
         replacementKeyCode(other.replacementKeyCode) {
@@ -944,7 +944,7 @@
             properties.add(Property(PROPERTY_NUMBER));
         } else {
             int32_t metaState;
-            status_t status = parseModifier(token, &metaState);
+            status_t status = parseModifier(token.string(), &metaState);
             if (status) {
                 ALOGE("%s: Expected a property name or modifier, got '%s'.",
                         mTokenizer->getLocation().string(), token.string());
@@ -1137,7 +1137,7 @@
     return NO_ERROR;
 }
 
-status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
+status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_t* outMetaState) {
     if (token == "base") {
         *outMetaState = 0;
         return NO_ERROR;
@@ -1145,7 +1145,7 @@
 
     int32_t combinedMeta = 0;
 
-    const char* str = token.string();
+    const char* str = token.c_str();
     const char* start = str;
     for (const char* cur = str; ; cur++) {
         char ch = *cur;
@@ -1164,7 +1164,7 @@
             }
             if (combinedMeta & metaState) {
                 ALOGE("%s: Duplicate modifier combination '%s'.",
-                        mTokenizer->getLocation().string(), token.string());
+                        mTokenizer->getLocation().string(), token.c_str());
                 return BAD_VALUE;
             }
 
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 2b2f13e..efca68d 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -49,13 +49,13 @@
 KeyLayoutMap::~KeyLayoutMap() {
 }
 
-status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
+status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {
     outMap->clear();
 
     Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
+    status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
     if (status) {
-        ALOGE("Error %d opening key layout map file %s.", status, filename.string());
+        ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
     } else {
         sp<KeyLayoutMap> map = new KeyLayoutMap();
         if (!map.get()) {
@@ -117,14 +117,15 @@
             return &mKeysByScanCode.valueAt(index);
         }
     }
-    return NULL;
+    return nullptr;
 }
 
-status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
+status_t KeyLayoutMap::findScanCodesForKey(
+        int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
     const size_t N = mKeysByScanCode.size();
     for (size_t i=0; i<N; i++) {
         if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
-            outScanCodes->add(mKeysByScanCode.keyAt(i));
+            outScanCodes->push_back(mKeysByScanCode.keyAt(i));
         }
     }
     return NO_ERROR;
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 11842ee..0c22bfe 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -45,22 +45,22 @@
         String8 keyLayoutName;
         if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
                 keyLayoutName)) {
-            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
+            status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
             if (status == NAME_NOT_FOUND) {
                 ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
                         "it was not found.",
-                        deviceIdenfifier.name.string(), keyLayoutName.string());
+                        deviceIdenfifier.name.c_str(), keyLayoutName.string());
             }
         }
 
         String8 keyCharacterMapName;
         if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
                 keyCharacterMapName)) {
-            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
+            status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
             if (status == NAME_NOT_FOUND) {
                 ALOGE("Configuration for keyboard device '%s' requested keyboard character "
                         "map '%s' but it was not found.",
-                        deviceIdenfifier.name.string(), keyLayoutName.string());
+                        deviceIdenfifier.name.c_str(), keyLayoutName.string());
             }
         }
 
@@ -70,30 +70,30 @@
     }
 
     // Try searching by device identifier.
-    if (probeKeyMap(deviceIdenfifier, String8::empty())) {
+    if (probeKeyMap(deviceIdenfifier, "")) {
         return OK;
     }
 
     // Fall back on the Generic key map.
     // TODO Apply some additional heuristics here to figure out what kind of
     //      generic key map to use (US English, etc.) for typical external keyboards.
-    if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
+    if (probeKeyMap(deviceIdenfifier, "Generic")) {
         return OK;
     }
 
     // Try the Virtual key map as a last resort.
-    if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
+    if (probeKeyMap(deviceIdenfifier, "Virtual")) {
         return OK;
     }
 
     // Give up!
     ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
-            deviceIdenfifier.name.string());
+            deviceIdenfifier.name.c_str());
     return NAME_NOT_FOUND;
 }
 
 bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyMapName) {
+        const std::string& keyMapName) {
     if (!haveKeyLayout()) {
         loadKeyLayout(deviceIdentifier, keyMapName);
     }
@@ -104,10 +104,10 @@
 }
 
 status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name) {
-    String8 path(getPath(deviceIdentifier, name,
+        const std::string& name) {
+    std::string path(getPath(deviceIdentifier, name,
             INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
-    if (path.isEmpty()) {
+    if (path.empty()) {
         return NAME_NOT_FOUND;
     }
 
@@ -116,15 +116,15 @@
         return status;
     }
 
-    keyLayoutFile.setTo(path);
+    keyLayoutFile = path;
     return OK;
 }
 
 status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name) {
-    String8 path(getPath(deviceIdentifier, name,
-            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
-    if (path.isEmpty()) {
+        const std::string& name) {
+    std::string path = getPath(deviceIdentifier, name,
+            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP);
+    if (path.empty()) {
         return NAME_NOT_FOUND;
     }
 
@@ -134,13 +134,13 @@
         return status;
     }
 
-    keyCharacterMapFile.setTo(path);
+    keyCharacterMapFile = path;
     return OK;
 }
 
-String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
-        const String8& name, InputDeviceConfigurationFileType type) {
-    return name.isEmpty()
+std::string KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
+        const std::string& name, InputDeviceConfigurationFileType type) {
+    return name.empty()
             ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
             : getInputDeviceConfigurationFilePathByName(name, type);
 }
@@ -174,7 +174,7 @@
         }
     }
 
-    return strstr(deviceIdentifier.name.string(), "-keypad");
+    return strstr(deviceIdentifier.name.c_str(), "-keypad");
 }
 
 static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
new file mode 100644
index 0000000..8a4298a
--- /dev/null
+++ b/libs/input/TouchVideoFrame.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/TouchVideoFrame.h>
+
+namespace android {
+
+TouchVideoFrame::TouchVideoFrame(uint32_t height, uint32_t width, std::vector<int16_t> data,
+        const struct timeval& timestamp) :
+         mHeight(height), mWidth(width),mData(std::move(data)), mTimestamp(timestamp) {
+}
+
+bool TouchVideoFrame::operator==(const TouchVideoFrame& rhs) const {
+    return mHeight == rhs.mHeight
+            && mWidth == rhs.mWidth
+            && mData == rhs.mData
+            && mTimestamp.tv_sec == rhs.mTimestamp.tv_sec
+            && mTimestamp.tv_usec == rhs.mTimestamp.tv_usec;
+}
+
+uint32_t TouchVideoFrame::getHeight() const { return mHeight; }
+
+uint32_t TouchVideoFrame::getWidth() const { return mWidth; }
+
+const std::vector<int16_t>& TouchVideoFrame::getData() const { return mData; }
+
+const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; }
+
+void TouchVideoFrame::rotate(int32_t orientation) {
+    switch (orientation) {
+        case DISPLAY_ORIENTATION_90:
+            rotateQuarterTurn(true /*clockwise*/);
+            break;
+        case DISPLAY_ORIENTATION_180:
+            rotate180();
+            break;
+        case DISPLAY_ORIENTATION_270:
+            rotateQuarterTurn(false /*clockwise*/);
+            break;
+    }
+}
+
+/**
+ * Rotate once clockwise by a quarter turn === rotate 90 degrees
+ * Rotate once counterclockwise by a quarter turn === rotate 270 degrees
+ * For a clockwise rotation:
+ *     An element at position (i, j) is rotated to (j, height - i - 1)
+ * For a counterclockwise rotation:
+ *     An element at position (i, j) is rotated to (width - j - 1, i)
+ */
+void TouchVideoFrame::rotateQuarterTurn(bool clockwise) {
+    std::vector<int16_t> rotated(mData.size());
+    for (size_t i = 0; i < mHeight; i++) {
+        for (size_t j = 0; j < mWidth; j++) {
+            size_t iRotated, jRotated;
+            if (clockwise) {
+                iRotated = j;
+                jRotated = mHeight - i - 1;
+            } else {
+                iRotated = mWidth - j - 1;
+                jRotated = i;
+            }
+            size_t indexRotated = iRotated * mHeight + jRotated;
+            rotated[indexRotated] = mData[i * mWidth + j];
+        }
+    }
+    mData = std::move(rotated);
+    std::swap(mHeight, mWidth);
+}
+
+/**
+ * An element at position (i, j) is rotated to (height - i - 1, width - j - 1)
+ * This is equivalent to moving element [i] to position [height * width - i - 1]
+ * Since element at [height * width - i - 1] would move to position [i],
+ * we can just swap elements [i] and [height * width - i - 1].
+ */
+void TouchVideoFrame::rotate180() {
+    if (mData.size() == 0) {
+        return;
+    }
+    // Just need to swap elements i and (height * width - 1 - i)
+    for (size_t i = 0; i < mData.size() / 2; i++) {
+        std::swap(mData[i], mData[mHeight * mWidth - 1 - i]);
+    }
+}
+
+} // namespace android
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index c70ace0..c6cc4fc 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -23,9 +23,11 @@
 // Log debug messages about the progress of the algorithm itself.
 #define DEBUG_STRATEGY 0
 
+#include <array>
 #include <inttypes.h>
 #include <limits.h>
 #include <math.h>
+#include <optional>
 
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
@@ -115,7 +117,7 @@
 
     // Allow the default strategy to be overridden using a system property for debugging.
     if (!strategy) {
-        int length = property_get("debug.velocitytracker.strategy", value, NULL);
+        int length = property_get("persist.input.velocitytracker.strategy", value, nullptr);
         if (length > 0) {
             strategy = value;
         } else {
@@ -139,7 +141,7 @@
 
 bool VelocityTracker::configureStrategy(const char* strategy) {
     mStrategy = createStrategy(strategy);
-    return mStrategy != NULL;
+    return mStrategy != nullptr;
 }
 
 VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
@@ -204,7 +206,7 @@
         // time to adjust to changes in direction.
         return new LegacyVelocityTrackerStrategy();
     }
-    return NULL;
+    return nullptr;
 }
 
 void VelocityTracker::clear() {
@@ -380,7 +382,16 @@
 
 void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
         const VelocityTracker::Position* positions) {
-    if (++mIndex == HISTORY_SIZE) {
+    if (mMovements[mIndex].eventTime != eventTime) {
+        // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
+        // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
+        // the new pointer. If the eventtimes for both events are identical, just update the data
+        // for this time.
+        // We only compare against the last value, as it is likely that addMovement is called
+        // in chronological order as events occur.
+        mIndex++;
+    }
+    if (mIndex == HISTORY_SIZE) {
         mIndex = 0;
     }
 
@@ -564,7 +575,9 @@
  * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to
  * the default implementation
  */
-static float solveUnweightedLeastSquaresDeg2(const float* x, const float* y, size_t count) {
+static std::optional<std::array<float, 3>> solveUnweightedLeastSquaresDeg2(
+        const float* x, const float* y, size_t count) {
+    // Solving y = a*x^2 + b*x + c
     float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
 
     for (size_t i = 0; i < count; i++) {
@@ -573,8 +586,8 @@
         float xi2 = xi*xi;
         float xi3 = xi2*xi;
         float xi4 = xi3*xi;
-        float xi2yi = xi2*yi;
         float xiyi = xi*yi;
+        float xi2yi = xi2*yi;
 
         sxi += xi;
         sxi2 += xi2;
@@ -591,13 +604,23 @@
     float Sx2y = sxi2yi - sxi2*syi / count;
     float Sx2x2 = sxi4 - sxi2*sxi2 / count;
 
-    float numerator = Sxy*Sx2x2 - Sx2y*Sxx2;
     float denominator = Sxx*Sx2x2 - Sxx2*Sxx2;
     if (denominator == 0) {
         ALOGW("division by 0 when computing velocity, Sxx=%f, Sx2x2=%f, Sxx2=%f", Sxx, Sx2x2, Sxx2);
-        return 0;
+        return std::nullopt;
     }
-    return numerator/denominator;
+    // Compute a
+    float numerator = Sx2y*Sxx - Sxy*Sxx2;
+    float a = numerator / denominator;
+
+    // Compute b
+    numerator = Sxy*Sx2x2 - Sx2y*Sxx2;
+    float b = numerator / denominator;
+
+    // Compute c
+    float c = syi/count - b * sxi/count - a * sxi2/count;
+
+    return std::make_optional(std::array<float, 3>({c, b, a}));
 }
 
 bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
@@ -640,20 +663,23 @@
     if (degree > m - 1) {
         degree = m - 1;
     }
-    if (degree >= 1) {
-        if (degree == 2 && mWeighting == WEIGHTING_NONE) { // optimize unweighted, degree=2 fit
+
+    if (degree == 2 && mWeighting == WEIGHTING_NONE) {
+        // Optimize unweighted, quadratic polynomial fit
+        std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x, m);
+        std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y, m);
+        if (xCoeff && yCoeff) {
             outEstimator->time = newestMovement.eventTime;
             outEstimator->degree = 2;
             outEstimator->confidence = 1;
-            outEstimator->xCoeff[0] = 0; // only slope is calculated, set rest of coefficients = 0
-            outEstimator->yCoeff[0] = 0;
-            outEstimator->xCoeff[1] = solveUnweightedLeastSquaresDeg2(time, x, m);
-            outEstimator->yCoeff[1] = solveUnweightedLeastSquaresDeg2(time, y, m);
-            outEstimator->xCoeff[2] = 0;
-            outEstimator->yCoeff[2] = 0;
+            for (size_t i = 0; i <= outEstimator->degree; i++) {
+                outEstimator->xCoeff[i] = (*xCoeff)[i];
+                outEstimator->yCoeff[i] = (*yCoeff)[i];
+            }
             return true;
         }
-
+    } else if (degree >= 1) {
+        // General case for an Nth degree polynomial fit
         float xdet, ydet;
         uint32_t n = degree + 1;
         if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
@@ -1000,7 +1026,16 @@
 
 void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
         const VelocityTracker::Position* positions) {
-    if (++mIndex == HISTORY_SIZE) {
+    if (mMovements[mIndex].eventTime != eventTime) {
+        // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
+        // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
+        // the new pointer. If the eventtimes for both events are identical, just update the data
+        // for this time.
+        // We only compare against the last value, as it is likely that addMovement is called
+        // in chronological order as events occur.
+        mIndex++;
+    }
+    if (mIndex == HISTORY_SIZE) {
         mIndex = 0;
     }
 
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 28ea717..865366b 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -28,10 +28,6 @@
 // Enables debug output for the parser.
 #define DEBUG_PARSER 0
 
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
 namespace android {
 
 static const char* WHITESPACE = " \t\r";
@@ -46,39 +42,28 @@
 VirtualKeyMap::~VirtualKeyMap() {
 }
 
-status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
-    *outMap = NULL;
-
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
-    if (status) {
-        ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
-    } else {
-        VirtualKeyMap* map = new VirtualKeyMap();
-        if (!map) {
-            ALOGE("Error allocating virtual key map.");
-            status = NO_MEMORY;
-        } else {
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
-            Parser parser(map, tokenizer);
-            status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
-            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
-            ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
-                    tokenizer->getFilename().string(), tokenizer->getLineNumber(),
-                    elapsedTime / 1000000.0);
-#endif
-            if (status) {
-                delete map;
-            } else {
-                *outMap = map;
-            }
-        }
-        delete tokenizer;
+std::unique_ptr<VirtualKeyMap> VirtualKeyMap::load(const std::string& filename) {
+    Tokenizer* t;
+    status_t status = Tokenizer::open(String8(filename.c_str()), &t);
+    if (status != OK) {
+        ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
+        return nullptr;
     }
-    return status;
+    std::unique_ptr<Tokenizer> tokenizer(t);
+    // Using 'new' to access a non-public constructor
+    std::unique_ptr<VirtualKeyMap> map(new VirtualKeyMap());
+    if (!map) {
+        ALOGE("Error allocating virtual key map.");
+        return nullptr;
+    }
+
+    Parser parser(map.get(), tokenizer.get());
+    status = parser.parse();
+    if (status != OK) {
+        return nullptr;
+    }
+
+    return map;
 }
 
 
@@ -127,7 +112,7 @@
                         "width=%d, height=%d",
                         defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
 #endif
-                mMap->mVirtualKeys.push(defn);
+                mMap->mVirtualKeys.push_back(defn);
             } while (consumeFieldDelimiterAndSkipWhitespace());
 
             if (!mTokenizer->isEol()) {
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index aca9521..ade931e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -1,11 +1,13 @@
 // Build the unit tests.
 cc_test {
     name: "libinput_tests",
-    test_per_src: true,
     srcs: [
         "InputChannel_test.cpp",
+        "InputDevice_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
+        "InputWindow_test.cpp",
+        "TouchVideoFrame_test.cpp",
         "VelocityTracker_test.cpp",
     ],
     cflags: [
@@ -34,5 +36,14 @@
         "-O0",
         "-Wall",
         "-Werror",
+        "-Wextra",
     ],
+    shared_libs: [
+        "libinput",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libui",
+        "libbase",
+    ]
 }
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 96c165c..f1675c0 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <array>
+
 #include "TestHelpers.h"
 
 #include <unistd.h>
@@ -155,5 +157,37 @@
             << "sendMessage should have returned DEAD_OBJECT";
 }
 
+TEST_F(InputChannelTest, SendAndReceive_MotionClassification) {
+    sp<InputChannel> serverChannel, clientChannel;
+    status_t result = InputChannel::openInputChannelPair("channel name",
+            serverChannel, clientChannel);
+    ASSERT_EQ(OK, result)
+            << "should have successfully opened a channel pair";
+
+    std::array<MotionClassification, 3> classifications = {
+        MotionClassification::NONE,
+        MotionClassification::AMBIGUOUS_GESTURE,
+        MotionClassification::DEEP_PRESS,
+    };
+
+    InputMessage serverMsg = {}, clientMsg;
+    serverMsg.header.type = InputMessage::TYPE_MOTION;
+    serverMsg.body.motion.seq = 1;
+    serverMsg.body.motion.pointerCount = 1;
+
+    for (MotionClassification classification : classifications) {
+        // Send and receive a message with classification
+        serverMsg.body.motion.classification = classification;
+        EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
+                << "server channel should be able to send message to client channel";
+
+        EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+                << "client channel should be able to receive message from server channel";
+        EXPECT_EQ(serverMsg.header.type, clientMsg.header.type);
+        EXPECT_EQ(classification, clientMsg.body.motion.classification) <<
+                "Expected to receive " << motionClassificationToString(classification);
+    }
+}
+
 
 } // namespace android
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
new file mode 100644
index 0000000..c174ae9
--- /dev/null
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <gtest/gtest.h>
+#include <input/InputDevice.h>
+
+namespace android {
+
+// --- InputDeviceIdentifierTest ---
+
+TEST(InputDeviceIdentifierTest, getCanonicalName) {
+    InputDeviceIdentifier identifier;
+    identifier.name = "test device";
+    ASSERT_EQ(std::string("test_device"), identifier.getCanonicalName());
+
+    identifier.name = "deviceName-123 version_C!";
+    ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName());
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index fd3b7c8..2b75c82 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <math.h>
 
 #include <binder/Parcel.h>
@@ -22,11 +23,10 @@
 
 namespace android {
 
-class BaseTest : public testing::Test {
-protected:
-    virtual void SetUp() { }
-    virtual void TearDown() { }
-};
+// Default display id.
+static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+
+class BaseTest : public testing::Test { };
 
 // --- PointerCoordsTest ---
 
@@ -178,13 +178,14 @@
     // Initialize and get properties.
     const nsecs_t ARBITRARY_DOWN_TIME = 1;
     const nsecs_t ARBITRARY_EVENT_TIME = 2;
-    event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
+    event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, AKEY_EVENT_ACTION_DOWN,
             AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
             AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
 
     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
     ASSERT_EQ(2, event.getDeviceId());
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
+    ASSERT_EQ(DISPLAY_ID, event.getDisplayId());
     ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
     ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
     ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
@@ -197,6 +198,11 @@
     // Set source.
     event.setSource(AINPUT_SOURCE_JOYSTICK);
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+
+    // Set display id.
+    constexpr int32_t newDisplayId = 2;
+    event.setDisplayId(newDisplayId);
+    ASSERT_EQ(newDisplayId, event.getDisplayId());
 }
 
 
@@ -248,10 +254,10 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
-    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0,
+    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
             AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
-            X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+            MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
             ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
             2, pointerProperties, pointerCoords);
 
@@ -301,11 +307,13 @@
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
     ASSERT_EQ(2, event->getDeviceId());
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
+    ASSERT_EQ(DISPLAY_ID, event->getDisplayId());
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
     ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
     ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
     ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
     ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
+    ASSERT_EQ(MotionClassification::NONE, event->getClassification());
     ASSERT_EQ(X_OFFSET, event->getXOffset());
     ASSERT_EQ(Y_OFFSET, event->getYOffset());
     ASSERT_EQ(2.0f, event->getXPrecision());
@@ -434,6 +442,11 @@
     event.setSource(AINPUT_SOURCE_JOYSTICK);
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
 
+    // Set displayId.
+    constexpr int32_t newDisplayId = 2;
+    event.setDisplayId(newDisplayId);
+    ASSERT_EQ(newDisplayId, event.getDisplayId());
+
     // Set action.
     event.setAction(AMOTION_EVENT_ACTION_CANCEL);
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
@@ -557,8 +570,11 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
+    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
+            0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
+            AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+            0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
@@ -591,4 +607,30 @@
     ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
 }
 
+TEST_F(MotionEventTest, Initialize_SetsClassification) {
+    std::array<MotionClassification, 3> classifications = {
+            MotionClassification::NONE,
+            MotionClassification::AMBIGUOUS_GESTURE,
+            MotionClassification::DEEP_PRESS,
+    };
+
+    MotionEvent event;
+    constexpr size_t pointerCount = 1;
+    PointerProperties pointerProperties[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerProperties[i].id = i;
+        pointerCoords[i].clear();
+    }
+
+    for (MotionClassification classification : classifications) {
+        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+                AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
+                classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/,
+                pointerCount, pointerProperties, pointerCoords);
+        ASSERT_EQ(classification, event.getClassification());
+    }
+}
+
 } // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index c532241..f2cd1be 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -46,12 +46,12 @@
     virtual void TearDown() {
         if (mPublisher) {
             delete mPublisher;
-            mPublisher = NULL;
+            mPublisher = nullptr;
         }
 
         if (mConsumer) {
             delete mConsumer;
-            mConsumer = NULL;
+            mConsumer = nullptr;
         }
 
         serverChannel.clear();
@@ -70,32 +70,31 @@
 void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
     status_t status;
 
-    const uint32_t seq = 15;
-    const int32_t deviceId = 1;
-    const int32_t source = AINPUT_SOURCE_KEYBOARD;
-    const int32_t action = AKEY_EVENT_ACTION_DOWN;
-    const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
-    const int32_t keyCode = AKEYCODE_ENTER;
-    const int32_t scanCode = 13;
-    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
-    const int32_t repeatCount = 1;
-    const nsecs_t downTime = 3;
-    const nsecs_t eventTime = 4;
+    constexpr uint32_t seq = 15;
+    constexpr int32_t deviceId = 1;
+    constexpr int32_t source = AINPUT_SOURCE_KEYBOARD;
+    constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
+    constexpr int32_t action = AKEY_EVENT_ACTION_DOWN;
+    constexpr int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
+    constexpr int32_t keyCode = AKEYCODE_ENTER;
+    constexpr int32_t scanCode = 13;
+    constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+    constexpr int32_t repeatCount = 1;
+    constexpr nsecs_t downTime = 3;
+    constexpr nsecs_t eventTime = 4;
 
-    status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
+    status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, action, flags,
             keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
     ASSERT_EQ(OK, status)
             << "publisher publishKeyEvent should return OK";
 
     uint32_t consumeSeq;
     InputEvent* event;
-    int32_t displayId;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
-            &displayId);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
-    ASSERT_TRUE(event != NULL)
+    ASSERT_TRUE(event != nullptr)
             << "consumer should have returned non-NULL event";
     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
             << "consumer should have returned a key event";
@@ -104,6 +103,7 @@
     EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(deviceId, keyEvent->getDeviceId());
     EXPECT_EQ(source, keyEvent->getSource());
+    EXPECT_EQ(displayId, keyEvent->getDisplayId());
     EXPECT_EQ(action, keyEvent->getAction());
     EXPECT_EQ(flags, keyEvent->getFlags());
     EXPECT_EQ(keyCode, keyEvent->getKeyCode());
@@ -131,23 +131,24 @@
 void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
     status_t status;
 
-    const uint32_t seq = 15;
-    const int32_t deviceId = 1;
-    const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
-    int32_t displayId = 0;
-    const int32_t action = AMOTION_EVENT_ACTION_MOVE;
-    const int32_t actionButton = 0;
-    const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-    const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
-    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
-    const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
-    const float xOffset = -10;
-    const float yOffset = -20;
-    const float xPrecision = 0.25;
-    const float yPrecision = 0.5;
-    const nsecs_t downTime = 3;
-    const size_t pointerCount = 3;
-    const nsecs_t eventTime = 4;
+    constexpr uint32_t seq = 15;
+    constexpr int32_t deviceId = 1;
+    constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
+    constexpr int32_t action = AMOTION_EVENT_ACTION_MOVE;
+    constexpr int32_t actionButton = 0;
+    constexpr int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+    constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
+    constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+    constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
+    constexpr MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE;
+    constexpr float xOffset = -10;
+    constexpr float yOffset = -20;
+    constexpr float xPrecision = 0.25;
+    constexpr float yPrecision = 0.5;
+    constexpr nsecs_t downTime = 3;
+    constexpr size_t pointerCount = 3;
+    constexpr nsecs_t eventTime = 4;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
     for (size_t i = 0; i < pointerCount; i++) {
@@ -168,20 +169,19 @@
     }
 
     status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
-            flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
-            downTime, eventTime, pointerCount,
+            flags, edgeFlags, metaState, buttonState, classification,
+            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount,
             pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
     uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
-            &displayId);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
-    ASSERT_TRUE(event != NULL)
+    ASSERT_TRUE(event != nullptr)
             << "consumer should have returned non-NULL event";
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
             << "consumer should have returned a motion event";
@@ -190,11 +190,13 @@
     EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(deviceId, motionEvent->getDeviceId());
     EXPECT_EQ(source, motionEvent->getSource());
+    EXPECT_EQ(displayId, motionEvent->getDisplayId());
     EXPECT_EQ(action, motionEvent->getAction());
     EXPECT_EQ(flags, motionEvent->getFlags());
     EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
     EXPECT_EQ(metaState, motionEvent->getMetaState());
     EXPECT_EQ(buttonState, motionEvent->getButtonState());
+    EXPECT_EQ(classification, motionEvent->getClassification());
     EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
     EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
     EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -264,7 +266,8 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -276,7 +279,8 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -293,7 +297,8 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
new file mode 100644
index 0000000..6db18ab
--- /dev/null
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
+
+#include <input/InputWindow.h>
+#include <input/InputTransport.h>
+
+namespace android {
+namespace test {
+
+TEST(InputWindowInfo, ParcellingWithoutToken) {
+    InputWindowInfo i;
+    i.token = nullptr;
+
+    Parcel p;
+    ASSERT_EQ(OK, i.write(p));
+    p.setDataPosition(0);
+    InputWindowInfo i2 = InputWindowInfo::read(p);
+    ASSERT_TRUE(i2.token == nullptr);
+}
+
+TEST(InputWindowInfo, Parcelling) {
+    sp<IBinder> touchableRegionCropHandle = new BBinder();
+    InputWindowInfo i;
+    i.token = new BBinder();
+    i.name = "Foobar";
+    i.layoutParamsFlags = 7;
+    i.layoutParamsType = 39;
+    i.dispatchingTimeout = 12;
+    i.frameLeft = 93;
+    i.frameTop = 34;
+    i.frameRight = 16;
+    i.frameBottom = 19;
+    i.surfaceInset = 17;
+    i.globalScaleFactor = 0.3;
+    i.windowXScale = 0.4;
+    i.windowYScale = 0.5;
+    i.visible = false;
+    i.canReceiveKeys = false;
+    i.hasFocus = false;
+    i.hasWallpaper = false;
+    i.paused = false;
+    i.layer = 7;
+    i.ownerPid = 19;
+    i.ownerUid = 24;
+    i.inputFeatures = 29;
+    i.displayId = 34;
+    i.portalToDisplayId = 2;
+    i.replaceTouchableRegionWithCrop = true;
+    i.touchableRegionCropHandle = touchableRegionCropHandle;
+
+    Parcel p;
+    i.write(p);
+
+    p.setDataPosition(0);
+    InputWindowInfo i2 = InputWindowInfo::read(p);
+    ASSERT_EQ(i.token, i2.token);
+    ASSERT_EQ(i.name, i2.name);
+    ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
+    ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
+    ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
+    ASSERT_EQ(i.frameLeft, i2.frameLeft);
+    ASSERT_EQ(i.frameTop, i2.frameTop);
+    ASSERT_EQ(i.frameRight, i2.frameRight);
+    ASSERT_EQ(i.frameBottom, i2.frameBottom);
+    ASSERT_EQ(i.surfaceInset, i2.surfaceInset);
+    ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
+    ASSERT_EQ(i.windowXScale, i2.windowXScale);
+    ASSERT_EQ(i.windowYScale, i2.windowYScale);
+    ASSERT_EQ(i.visible, i2.visible);
+    ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
+    ASSERT_EQ(i.hasFocus, i2.hasFocus);
+    ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
+    ASSERT_EQ(i.paused, i2.paused);
+    ASSERT_EQ(i.layer, i2.layer);
+    ASSERT_EQ(i.ownerPid, i2.ownerPid);
+    ASSERT_EQ(i.ownerUid, i2.ownerUid);
+    ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
+    ASSERT_EQ(i.displayId, i2.displayId);
+    ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId);
+    ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
+    ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 12a6782..62023fb 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -57,7 +57,8 @@
   CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
   CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
   CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
-  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+  CHECK_OFFSET(InputMessage::Body::Motion, classification, 48);
+  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 52);
   CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
   CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
   CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
diff --git a/libs/input/tests/TestHelpers.h b/libs/input/tests/TestHelpers.h
index fe87bb9..343d81f 100644
--- a/libs/input/tests/TestHelpers.h
+++ b/libs/input/tests/TestHelpers.h
@@ -62,7 +62,7 @@
     int mDelayMillis;
 
 public:
-    DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
+    explicit DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
 
 protected:
     virtual ~DelayedTask() { }
diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp
new file mode 100644
index 0000000..815424e
--- /dev/null
+++ b/libs/input/tests/TouchVideoFrame_test.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <input/TouchVideoFrame.h>
+
+namespace android {
+namespace test {
+
+static const struct timeval TIMESTAMP = {1, 2};
+
+TEST(TouchVideoFrame, Constructor) {
+    const std::vector<int16_t> data = {1, 2, 3, 4, 5, 6};
+    constexpr uint32_t height = 3;
+    constexpr uint32_t width = 2;
+
+    TouchVideoFrame frame(height, width, data, TIMESTAMP);
+
+    ASSERT_EQ(data, frame.getData());
+    ASSERT_EQ(height, frame.getHeight());
+    ASSERT_EQ(width, frame.getWidth());
+    ASSERT_EQ(TIMESTAMP.tv_sec, frame.getTimestamp().tv_sec);
+    ASSERT_EQ(TIMESTAMP.tv_usec, frame.getTimestamp().tv_usec);
+}
+
+TEST(TouchVideoFrame, Equality) {
+    const std::vector<int16_t> data = {1, 2, 3, 4, 5, 6};
+    constexpr uint32_t height = 3;
+    constexpr uint32_t width = 2;
+    TouchVideoFrame frame(height, width, data, TIMESTAMP);
+
+    TouchVideoFrame identicalFrame(height, width, data, TIMESTAMP);
+    ASSERT_EQ(frame, identicalFrame);
+
+    // The two cases below create an invalid frame, but it is OK for comparison purposes.
+    // There aren't any checks currently enforced on the frame dimensions and data
+    // Change height
+    TouchVideoFrame changedHeightFrame(height + 1, width, data, TIMESTAMP);
+    ASSERT_FALSE(frame == changedHeightFrame);
+
+    // Change width
+    TouchVideoFrame changedWidthFrame(height, width + 1, data, TIMESTAMP);
+    ASSERT_FALSE(frame == changedWidthFrame);
+
+    // Change data
+    const std::vector<int16_t> differentData = {1, 2, 3, 3, 5, 6};
+    TouchVideoFrame changedDataFrame(height, width, differentData, TIMESTAMP);
+    ASSERT_FALSE(frame == changedDataFrame);
+
+    // Change timestamp
+    const struct timeval differentTimestamp = {TIMESTAMP.tv_sec + 1, TIMESTAMP.tv_usec + 1};
+    TouchVideoFrame changedTimestampFrame(height, width, data, differentTimestamp);
+    ASSERT_FALSE(frame == changedTimestampFrame);
+}
+
+// --- Rotate 90 degrees ---
+
+TEST(TouchVideoFrame, Rotate90_0x0) {
+    TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+    TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_1x1) {
+    TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+    TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_2x2) {
+    TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_3x2) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_3x2_4times) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    frame.rotate(DISPLAY_ORIENTATION_90);
+    ASSERT_EQ(frame, frameOriginal);
+}
+
+// --- Rotate 180 degrees ---
+
+TEST(TouchVideoFrame, Rotate180_0x0) {
+    TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+    TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_1x1) {
+    TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+    TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_2x2) {
+    TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 2, {4, 3, 2, 1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x2) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameRotated(3, 2, {6, 5, 4, 3, 2, 1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x2_2times) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameOriginal);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x3) {
+    TouchVideoFrame frame(3, 3, {1, 2, 3, 4, 5, 6, 7, 8, 9}, TIMESTAMP);
+    TouchVideoFrame frameRotated(3, 3, {9, 8, 7, 6, 5, 4, 3, 2, 1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_180);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+// --- Rotate 270 degrees ---
+
+TEST(TouchVideoFrame, Rotate270_0x0) {
+    TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+    TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_1x1) {
+    TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+    TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_2x2) {
+    TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_3x2) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_3x2_4times) {
+    TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    frame.rotate(DISPLAY_ORIENTATION_270);
+    ASSERT_EQ(frame, frameOriginal);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 43b6012..368446f 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,97 +16,188 @@
 
 #define LOG_TAG "VelocityTracker_test"
 
+#include <array>
+#include <chrono>
 #include <math.h>
 
 #include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 #include <input/VelocityTracker.h>
 
+using namespace std::chrono_literals;
 using android::base::StringPrintf;
 
 namespace android {
 
+constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; // default display id
+
 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;
 
+// estimate coefficients must be within 0.001% of the target value
+constexpr float COEFFICIENT_TOLERANCE = 0.00001;
+
 // --- 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);
-    }
+/*
+ * Similar to EXPECT_NEAR, but ensures that the difference between the two float values
+ * is at most a certain fraction of the target value.
+ * If fraction is zero, require exact match.
+ */
+static void EXPECT_NEAR_BY_FRACTION(float actual, float target, float fraction) {
+    float tolerance = fabsf(target * fraction);
 
-    // 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 (target == 0 && fraction != 0) {
+        // If target is zero, this would force actual == target, which is too harsh.
+        // Relax this requirement a little. The value is determined empirically from the
+        // coefficients computed by the quadratic least squares algorithms.
+        tolerance = 1E-6;
     }
-    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);
+    EXPECT_NEAR(actual, target, tolerance);
 }
 
-void failWithMessage(std::string message) {
-    FAIL() << message; // cannot do this directly from a non-void function
+static void checkVelocity(float Vactual, float Vtarget) {
+    EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE);
+}
+
+static void checkCoefficient(float actual, float target) {
+    EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE);
 }
 
 struct Position {
-      nsecs_t time;
-      float x;
-      float y;
+    float x;
+    float y;
+
+    /**
+     * If both values are NAN, then this is considered to be an empty entry (no pointer data).
+     * If only one of the values is NAN, this is still a valid entry,
+     * because we may only care about a single axis.
+     */
+    bool isValid() const {
+        return !(isnan(x) && isnan(y));
+    }
 };
 
+struct MotionEventEntry {
+    std::chrono::nanoseconds eventTime;
+    std::vector<Position> positions;
+};
 
-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));
+static BitSet32 getValidPointers(const std::vector<Position>& positions) {
+    BitSet32 pointers;
+    for (size_t i = 0; i < positions.size(); i++) {
+        if (positions[i].isValid()) {
+            pointers.markBit(i);
+        }
     }
-
-    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;
+    return pointers;
 }
 
-static void computeAndCheckVelocity(const Position* positions, size_t numSamples,
-            int32_t axis, float targetVelocity) {
-    VelocityTracker vt(nullptr);
+static uint32_t getChangingPointerId(BitSet32 pointers, BitSet32 otherPointers) {
+    BitSet32 difference(pointers.value ^ otherPointers.value);
+    uint32_t pointerId = difference.clearFirstMarkedBit();
+    EXPECT_EQ(0U, difference.value) << "Only 1 pointer can enter or leave at a time";
+    return pointerId;
+}
+
+static int32_t resolveAction(const std::vector<Position>& lastPositions,
+        const std::vector<Position>& currentPositions,
+        const std::vector<Position>& nextPositions) {
+    BitSet32 pointers = getValidPointers(currentPositions);
+    const uint32_t pointerCount = pointers.count();
+
+    BitSet32 lastPointers = getValidPointers(lastPositions);
+    const uint32_t lastPointerCount = lastPointers.count();
+    if (lastPointerCount < pointerCount) {
+        // A new pointer is down
+        uint32_t pointerId = getChangingPointerId(pointers, lastPointers);
+        return AMOTION_EVENT_ACTION_POINTER_DOWN |
+                (pointerId << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+    }
+
+    BitSet32 nextPointers = getValidPointers(nextPositions);
+    const uint32_t nextPointerCount = nextPointers.count();
+    if (pointerCount > nextPointerCount) {
+        // An existing pointer is leaving
+        uint32_t pointerId = getChangingPointerId(pointers, nextPointers);
+        return AMOTION_EVENT_ACTION_POINTER_UP |
+                (pointerId << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+    }
+
+    return AMOTION_EVENT_ACTION_MOVE;
+}
+
+static std::vector<MotionEvent> createMotionEventStream(
+        const std::vector<MotionEventEntry>& motions) {
+    if (motions.empty()) {
+        ADD_FAILURE() << "Need at least 1 sample to create a MotionEvent. Received empty vector.";
+    }
+
+    std::vector<MotionEvent> events;
+    for (size_t i = 0; i < motions.size(); i++) {
+        const MotionEventEntry& entry = motions[i];
+        BitSet32 pointers = getValidPointers(entry.positions);
+        const uint32_t pointerCount = pointers.count();
+
+        int32_t action;
+        if (i == 0) {
+            action = AMOTION_EVENT_ACTION_DOWN;
+            EXPECT_EQ(1U, pointerCount) << "First event should only have 1 pointer";
+        } else if (i == motions.size() - 1) {
+            EXPECT_EQ(1U, pointerCount) << "Last event should only have 1 pointer";
+            action = AMOTION_EVENT_ACTION_UP;
+        } else {
+            const MotionEventEntry& previousEntry = motions[i-1];
+            const MotionEventEntry& nextEntry = motions[i+1];
+            action = resolveAction(previousEntry.positions, entry.positions, nextEntry.positions);
+        }
+
+        PointerCoords coords[pointerCount];
+        PointerProperties properties[pointerCount];
+        uint32_t pointerIndex = 0;
+        while(!pointers.isEmpty()) {
+            uint32_t pointerId = pointers.clearFirstMarkedBit();
+
+            coords[pointerIndex].clear();
+            // We are treating column positions as pointerId
+            EXPECT_TRUE(entry.positions[pointerId].isValid()) <<
+                    "The entry at pointerId must be valid";
+            coords[pointerIndex].setAxisValue(AMOTION_EVENT_AXIS_X, entry.positions[pointerId].x);
+            coords[pointerIndex].setAxisValue(AMOTION_EVENT_AXIS_Y, entry.positions[pointerId].y);
+
+            properties[pointerIndex].id = pointerId;
+            properties[pointerIndex].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+            pointerIndex++;
+        }
+        EXPECT_EQ(pointerIndex, pointerCount);
+
+        MotionEvent event;
+        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+                action, 0 /*actionButton*/, 0 /*flags*/,
+                AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
+                MotionClassification::NONE,
+                0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+                0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords);
+
+        events.emplace_back(event);
+    }
+
+    return events;
+}
+
+static void computeAndCheckVelocity(const char* strategy,
+        const std::vector<MotionEventEntry>& motions, int32_t axis, float targetVelocity) {
+    VelocityTracker vt(strategy);
     float Vx, Vy;
 
-    MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
-    vt.addMovement(event);
+    std::vector<MotionEvent> events = createMotionEventStream(motions);
+    for (MotionEvent event : events) {
+        vt.addMovement(&event);
+    }
 
     vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);
 
@@ -120,46 +211,61 @@
     default:
         FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
     }
-    delete event;
+}
+
+static void computeAndCheckQuadraticEstimate(const std::vector<MotionEventEntry>& motions,
+        const std::array<float, 3>& coefficients) {
+    VelocityTracker vt("lsq2");
+    std::vector<MotionEvent> events = createMotionEventStream(motions);
+    for (MotionEvent event : events) {
+        vt.addMovement(&event);
+    }
+    VelocityTracker::Estimator estimator;
+    EXPECT_TRUE(vt.getEstimator(0, &estimator));
+    for (size_t i = 0; i< coefficients.size(); i++) {
+        checkCoefficient(estimator.xCoeff[i], coefficients[i]);
+        checkCoefficient(estimator.yCoeff[i], coefficients[i]);
+    }
 }
 
 /*
  * ================== VelocityTracker tests generated manually =====================================
  */
- // @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
-TEST_F(VelocityTrackerTest, DISABLED_ThreePointsPositiveVelocityTest) {
+TEST_F(VelocityTrackerTest, 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 },
+    std::vector<MotionEventEntry> motions = {
+        {0ms, {{ 273, NAN}}},
+        {12585us, {{293, NAN}}},
+        {14730us, {{293, NAN}}},
+        {14730us, {{293, NAN}}}, // ACTION_UP
     };
-    size_t count = sizeof(values) / sizeof(Position);
-    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 1600);
+    computeAndCheckVelocity("impulse", motions, 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{293, NAN}} },
+        { 6132us, {{293, NAN}} },
+        { 11283us, {{293, NAN}} },
+        { 11283us, {{293, NAN}} }, // ACTION_UP
     };
-    size_t count = sizeof(values) / sizeof(Position);
-    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 0);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 0);
+    computeAndCheckVelocity("lsq2", motions, 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{0, NAN}} },
+        { 10ms, {{5, NAN}} },
+        { 20ms, {{10, NAN}} },
+        { 20ms, {{10, NAN}} }, // ACTION_UP
     };
-    size_t count = sizeof(values) / sizeof(Position);
-    computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_X, 500);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 500);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 500);
 }
 
 
@@ -171,24 +277,26 @@
  * 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.
+ *
+ * Another good way to generate this data is to use 'dumpsys input' just after the event has
+ * occurred.
  */
 
 // --------------- Recorded by hand on swordfish ---------------------------------------------------
-// @todo Currently disabled, enable when switching away from lsq2 VelocityTrackerStrategy
-TEST_F(VelocityTrackerTest, DISABLED_SwordfishFlingDown) {
+TEST_F(VelocityTrackerTest, 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{271, 96}} },
+        { 16071042ns, {{269.786346, 106.922775}} },
+        { 35648403ns, {{267.983063, 156.660034}} },
+        { 52313925ns, {{262.638397, 220.339081}} },
+        { 68976522ns, {{266.138824, 331.581116}} },
+        { 85639375ns, {{274.79245, 428.113159}} },
+        { 96948871ns, {{274.79245, 428.113159}} },
+        { 96948871ns, {{274.79245, 428.113159}} }, // ACTION_UP
     };
-    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);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 623.577637);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 5970.7309);
 }
 
 // --------------- Recorded by hand on sailfish, generated by a script -----------------------------
@@ -210,455 +318,591 @@
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235089067457000ns, {{528.00, 983.00}} },
+        { 235089084684000ns, {{527.00, 981.00}} },
+        { 235089093349000ns, {{527.00, 977.00}} },
+        { 235089095677625ns, {{527.00, 975.93}} },
+        { 235089101859000ns, {{527.00, 970.00}} },
+        { 235089110378000ns, {{528.00, 960.00}} },
+        { 235089112497111ns, {{528.25, 957.51}} },
+        { 235089118760000ns, {{531.00, 946.00}} },
+        { 235089126686000ns, {{535.00, 931.00}} },
+        { 235089129316820ns, {{536.33, 926.02}} },
+        { 235089135199000ns, {{540.00, 914.00}} },
+        { 235089144297000ns, {{546.00, 896.00}} },
+        { 235089146136443ns, {{547.21, 892.36}} },
+        { 235089152923000ns, {{553.00, 877.00}} },
+        { 235089160784000ns, {{559.00, 851.00}} },
+        { 235089162955851ns, {{560.66, 843.82}} },
+        { 235089162955851ns, {{560.66, 843.82}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 872.794617);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 951.698181);
+    computeAndCheckVelocity("impulse",motions, AMOTION_EVENT_AXIS_Y, -3604.819336);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -3044.966064);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235110560704000ns, {{522.00, 1107.00}} },
+        { 235110575764000ns, {{522.00, 1107.00}} },
+        { 235110584385000ns, {{522.00, 1107.00}} },
+        { 235110588421179ns, {{521.52, 1106.52}} },
+        { 235110592830000ns, {{521.00, 1106.00}} },
+        { 235110601385000ns, {{520.00, 1104.00}} },
+        { 235110605088160ns, {{519.14, 1102.27}} },
+        { 235110609952000ns, {{518.00, 1100.00}} },
+        { 235110618353000ns, {{517.00, 1093.00}} },
+        { 235110621755146ns, {{516.60, 1090.17}} },
+        { 235110627010000ns, {{517.00, 1081.00}} },
+        { 235110634785000ns, {{518.00, 1063.00}} },
+        { 235110638422450ns, {{518.87, 1052.58}} },
+        { 235110643161000ns, {{520.00, 1039.00}} },
+        { 235110651767000ns, {{524.00, 1011.00}} },
+        { 235110655089581ns, {{525.54, 1000.19}} },
+        { 235110660368000ns, {{530.00, 980.00}} },
+        { 235110660368000ns, {{530.00, 980.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -4096.583008);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -3455.094238);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 792536237000ns, {{580.00, 1317.00}} },
+        { 792541538987ns, {{580.63, 1311.94}} },
+        { 792544613000ns, {{581.00, 1309.00}} },
+        { 792552301000ns, {{583.00, 1295.00}} },
+        { 792558362309ns, {{585.13, 1282.92}} },
+        { 792560828000ns, {{586.00, 1278.00}} },
+        { 792569446000ns, {{589.00, 1256.00}} },
+        { 792575185095ns, {{591.54, 1241.41}} },
+        { 792578491000ns, {{593.00, 1233.00}} },
+        { 792587044000ns, {{597.00, 1211.00}} },
+        { 792592008172ns, {{600.28, 1195.92}} },
+        { 792594616000ns, {{602.00, 1188.00}} },
+        { 792603129000ns, {{607.00, 1167.00}} },
+        { 792608831290ns, {{609.48, 1155.83}} },
+        { 792612321000ns, {{611.00, 1149.00}} },
+        { 792620768000ns, {{615.00, 1131.00}} },
+        { 792625653873ns, {{617.32, 1121.73}} },
+        { 792629200000ns, {{619.00, 1115.00}} },
+        { 792629200000ns, {{619.00, 1115.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 574.33429);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 617.40564);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -2361.982666);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -2500.055664);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235160420675000ns, {{610.00, 1042.00}} },
+        { 235160428220000ns, {{609.00, 1026.00}} },
+        { 235160436544000ns, {{609.00, 1024.00}} },
+        { 235160441852394ns, {{609.64, 1020.82}} },
+        { 235160444878000ns, {{610.00, 1019.00}} },
+        { 235160452673000ns, {{613.00, 1006.00}} },
+        { 235160458519743ns, {{617.18, 992.06}} },
+        { 235160461061000ns, {{619.00, 986.00}} },
+        { 235160469798000ns, {{627.00, 960.00}} },
+        { 235160475186713ns, {{632.22, 943.02}} },
+        { 235160478051000ns, {{635.00, 934.00}} },
+        { 235160486489000ns, {{644.00, 906.00}} },
+        { 235160491853697ns, {{649.56, 890.56}} },
+        { 235160495177000ns, {{653.00, 881.00}} },
+        { 235160504148000ns, {{662.00, 858.00}} },
+        { 235160509231495ns, {{666.81, 845.37}} },
+        { 235160512603000ns, {{670.00, 837.00}} },
+        { 235160520366000ns, {{679.00, 814.00}} },
+        { 235160520366000ns, {{679.00, 814.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 1274.141724);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 1438.53186);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -3001.4348);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -3695.859619);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 847153808000ns, {{576.00, 1264.00}} },
+        { 847171174000ns, {{576.00, 1262.00}} },
+        { 847179640000ns, {{576.00, 1257.00}} },
+        { 847185187540ns, {{577.41, 1249.22}} },
+        { 847187487000ns, {{578.00, 1246.00}} },
+        { 847195710000ns, {{581.00, 1227.00}} },
+        { 847202027059ns, {{583.93, 1209.40}} },
+        { 847204324000ns, {{585.00, 1203.00}} },
+        { 847212672000ns, {{590.00, 1176.00}} },
+        { 847218861395ns, {{594.36, 1157.11}} },
+        { 847221190000ns, {{596.00, 1150.00}} },
+        { 847230484000ns, {{602.00, 1124.00}} },
+        { 847235701400ns, {{607.56, 1103.83}} },
+        { 847237986000ns, {{610.00, 1095.00}} },
+        { 847237986000ns, {{610.00, 1095.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -4280.07959);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -4241.004395);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235200532789000ns, {{507.00, 1084.00}} },
+        { 235200549221000ns, {{507.00, 1083.00}} },
+        { 235200557841000ns, {{507.00, 1081.00}} },
+        { 235200558051189ns, {{507.00, 1080.95}} },
+        { 235200566314000ns, {{507.00, 1078.00}} },
+        { 235200574876586ns, {{508.97, 1070.12}} },
+        { 235200575006000ns, {{509.00, 1070.00}} },
+        { 235200582900000ns, {{514.00, 1054.00}} },
+        { 235200591276000ns, {{525.00, 1023.00}} },
+        { 235200591701829ns, {{525.56, 1021.42}} },
+        { 235200600064000ns, {{542.00, 976.00}} },
+        { 235200608519000ns, {{563.00, 911.00}} },
+        { 235200608527086ns, {{563.02, 910.94}} },
+        { 235200616933000ns, {{590.00, 844.00}} },
+        { 235200616933000ns, {{590.00, 844.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -8715.686523);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -7639.026367);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 920922149000ns, {{561.00, 1412.00}} },
+        { 920930185000ns, {{559.00, 1377.00}} },
+        { 920930262463ns, {{558.98, 1376.66}} },
+        { 920938547000ns, {{559.00, 1371.00}} },
+        { 920947096857ns, {{562.91, 1342.68}} },
+        { 920947302000ns, {{563.00, 1342.00}} },
+        { 920955502000ns, {{577.00, 1272.00}} },
+        { 920963931021ns, {{596.87, 1190.54}} },
+        { 920963987000ns, {{597.00, 1190.00}} },
+        { 920972530000ns, {{631.00, 1093.00}} },
+        { 920980765511ns, {{671.31, 994.68}} },
+        { 920980906000ns, {{672.00, 993.00}} },
+        { 920989261000ns, {{715.00, 903.00}} },
+        { 920989261000ns, {{715.00, 903.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 5670.329102);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 5991.866699);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -13021.101562);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -15093.995117);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235247153233000ns, {{518.00, 1168.00}} },
+        { 235247170452000ns, {{517.00, 1167.00}} },
+        { 235247178908000ns, {{515.00, 1159.00}} },
+        { 235247179556213ns, {{514.85, 1158.39}} },
+        { 235247186821000ns, {{515.00, 1125.00}} },
+        { 235247195265000ns, {{521.00, 1051.00}} },
+        { 235247196389476ns, {{521.80, 1041.15}} },
+        { 235247203649000ns, {{538.00, 932.00}} },
+        { 235247212253000ns, {{571.00, 794.00}} },
+        { 235247213222491ns, {{574.72, 778.45}} },
+        { 235247220736000ns, {{620.00, 641.00}} },
+        { 235247220736000ns, {{620.00, 641.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -20286.958984);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -20494.587891);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235302568736000ns, {{529.00, 1167.00}} },
+        { 235302576644000ns, {{523.00, 1140.00}} },
+        { 235302579395063ns, {{520.91, 1130.61}} },
+        { 235302585140000ns, {{522.00, 1130.00}} },
+        { 235302593615000ns, {{527.00, 1065.00}} },
+        { 235302596207444ns, {{528.53, 1045.12}} },
+        { 235302602102000ns, {{559.00, 872.00}} },
+        { 235302610545000ns, {{652.00, 605.00}} },
+        { 235302613019881ns, {{679.26, 526.73}} },
+        { 235302613019881ns, {{679.26, 526.73}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -39295.941406);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -36461.421875);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235655749552755ns, {{582.00, 432.49}} },
+        { 235655750638000ns, {{582.00, 433.00}} },
+        { 235655758865000ns, {{582.00, 440.00}} },
+        { 235655766221523ns, {{581.16, 448.43}} },
+        { 235655767594000ns, {{581.00, 450.00}} },
+        { 235655776044000ns, {{580.00, 462.00}} },
+        { 235655782890696ns, {{579.18, 474.35}} },
+        { 235655784360000ns, {{579.00, 477.00}} },
+        { 235655792795000ns, {{578.00, 496.00}} },
+        { 235655799559531ns, {{576.27, 515.04}} },
+        { 235655800612000ns, {{576.00, 518.00}} },
+        { 235655809535000ns, {{574.00, 542.00}} },
+        { 235655816988015ns, {{572.17, 564.86}} },
+        { 235655817685000ns, {{572.00, 567.00}} },
+        { 235655825981000ns, {{569.00, 595.00}} },
+        { 235655833808653ns, {{566.26, 620.60}} },
+        { 235655834541000ns, {{566.00, 623.00}} },
+        { 235655842893000ns, {{563.00, 649.00}} },
+        { 235655842893000ns, {{563.00, 649.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -419.749695);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -398.303894);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 3309.016357);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 3969.099854);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235671152083370ns, {{485.24, 558.28}} },
+        { 235671154126000ns, {{485.00, 559.00}} },
+        { 235671162497000ns, {{484.00, 566.00}} },
+        { 235671168750511ns, {{483.27, 573.29}} },
+        { 235671171071000ns, {{483.00, 576.00}} },
+        { 235671179390000ns, {{482.00, 588.00}} },
+        { 235671185417210ns, {{481.31, 598.98}} },
+        { 235671188173000ns, {{481.00, 604.00}} },
+        { 235671196371000ns, {{480.00, 624.00}} },
+        { 235671202084196ns, {{479.27, 639.98}} },
+        { 235671204235000ns, {{479.00, 646.00}} },
+        { 235671212554000ns, {{478.00, 673.00}} },
+        { 235671219471011ns, {{476.39, 697.12}} },
+        { 235671221159000ns, {{476.00, 703.00}} },
+        { 235671229592000ns, {{474.00, 734.00}} },
+        { 235671236281462ns, {{472.43, 758.38}} },
+        { 235671238098000ns, {{472.00, 765.00}} },
+        { 235671246532000ns, {{470.00, 799.00}} },
+        { 235671246532000ns, {{470.00, 799.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -262.80426);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -243.665344);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 4215.682129);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4587.986816);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 170983201000ns, {{557.00, 533.00}} },
+        { 171000668000ns, {{556.00, 534.00}} },
+        { 171007359750ns, {{554.73, 535.27}} },
+        { 171011197000ns, {{554.00, 536.00}} },
+        { 171017660000ns, {{552.00, 540.00}} },
+        { 171024201831ns, {{549.97, 544.73}} },
+        { 171027333000ns, {{549.00, 547.00}} },
+        { 171034603000ns, {{545.00, 557.00}} },
+        { 171041043371ns, {{541.98, 567.55}} },
+        { 171043147000ns, {{541.00, 571.00}} },
+        { 171051052000ns, {{536.00, 586.00}} },
+        { 171051052000ns, {{536.00, 586.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -723.413513);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -651.038452);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 2091.502441);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 1934.517456);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235695280333000ns, {{558.00, 451.00}} },
+        { 235695283971237ns, {{558.43, 454.45}} },
+        { 235695289038000ns, {{559.00, 462.00}} },
+        { 235695297388000ns, {{561.00, 478.00}} },
+        { 235695300638465ns, {{561.83, 486.25}} },
+        { 235695305265000ns, {{563.00, 498.00}} },
+        { 235695313591000ns, {{564.00, 521.00}} },
+        { 235695317305492ns, {{564.43, 532.68}} },
+        { 235695322181000ns, {{565.00, 548.00}} },
+        { 235695330709000ns, {{565.00, 577.00}} },
+        { 235695333972227ns, {{565.00, 588.10}} },
+        { 235695339250000ns, {{565.00, 609.00}} },
+        { 235695347839000ns, {{565.00, 642.00}} },
+        { 235695351313257ns, {{565.00, 656.18}} },
+        { 235695356412000ns, {{565.00, 677.00}} },
+        { 235695364899000ns, {{563.00, 710.00}} },
+        { 235695368118682ns, {{562.24, 722.52}} },
+        { 235695373403000ns, {{564.00, 744.00}} },
+        { 235695373403000ns, {{564.00, 744.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 4254.639648);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4698.415039);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235709624766000ns, {{535.00, 579.00}} },
+        { 235709642256000ns, {{534.00, 580.00}} },
+        { 235709643350278ns, {{533.94, 580.06}} },
+        { 235709650760000ns, {{532.00, 584.00}} },
+        { 235709658615000ns, {{530.00, 593.00}} },
+        { 235709660170495ns, {{529.60, 594.78}} },
+        { 235709667095000ns, {{527.00, 606.00}} },
+        { 235709675616000ns, {{524.00, 628.00}} },
+        { 235709676983261ns, {{523.52, 631.53}} },
+        { 235709684289000ns, {{521.00, 652.00}} },
+        { 235709692763000ns, {{518.00, 682.00}} },
+        { 235709693804993ns, {{517.63, 685.69}} },
+        { 235709701438000ns, {{515.00, 709.00}} },
+        { 235709709830000ns, {{512.00, 739.00}} },
+        { 235709710626776ns, {{511.72, 741.85}} },
+        { 235709710626776ns, {{511.72, 741.85}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -430.440247);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -447.600311);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 3953.859375);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4316.155273);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235727628927000ns, {{540.00, 440.00}} },
+        { 235727636810000ns, {{537.00, 454.00}} },
+        { 235727646176000ns, {{536.00, 454.00}} },
+        { 235727653586628ns, {{535.12, 456.65}} },
+        { 235727654557000ns, {{535.00, 457.00}} },
+        { 235727663024000ns, {{534.00, 465.00}} },
+        { 235727670410103ns, {{533.04, 479.45}} },
+        { 235727670691000ns, {{533.00, 480.00}} },
+        { 235727679255000ns, {{531.00, 501.00}} },
+        { 235727687233704ns, {{529.09, 526.73}} },
+        { 235727687628000ns, {{529.00, 528.00}} },
+        { 235727696113000ns, {{526.00, 558.00}} },
+        { 235727704057546ns, {{523.18, 588.98}} },
+        { 235727704576000ns, {{523.00, 591.00}} },
+        { 235727713099000ns, {{520.00, 626.00}} },
+        { 235727720880776ns, {{516.33, 655.36}} },
+        { 235727721580000ns, {{516.00, 658.00}} },
+        { 235727721580000ns, {{516.00, 658.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 4484.617676);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4927.92627);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235762352849000ns, {{467.00, 286.00}} },
+        { 235762360250000ns, {{443.00, 344.00}} },
+        { 235762362787412ns, {{434.77, 363.89}} },
+        { 235762368807000ns, {{438.00, 359.00}} },
+        { 235762377220000ns, {{425.00, 423.00}} },
+        { 235762379608561ns, {{421.31, 441.17}} },
+        { 235762385698000ns, {{412.00, 528.00}} },
+        { 235762394133000ns, {{406.00, 648.00}} },
+        { 235762396429369ns, {{404.37, 680.67}} },
+        { 235762396429369ns, {{404.37, 680.67}} }, //ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 14227.0224);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 16064.685547);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 235772487188000ns, {{576.00, 204.00}} },
+        { 235772495159000ns, {{553.00, 236.00}} },
+        { 235772503568000ns, {{551.00, 240.00}} },
+        { 235772508192247ns, {{545.55, 254.17}} },
+        { 235772512051000ns, {{541.00, 266.00}} },
+        { 235772520794000ns, {{520.00, 337.00}} },
+        { 235772525015263ns, {{508.92, 394.43}} },
+        { 235772529174000ns, {{498.00, 451.00}} },
+        { 235772537635000ns, {{484.00, 589.00}} },
+        { 235772537635000ns, {{484.00, 589.00}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 18660.048828);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 16918.439453);
 }
 
 
 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 },
+    std::vector<MotionEventEntry> motions = {
+        { 507650295000ns, {{628.00, 233.00}} },
+        { 507658234000ns, {{605.00, 269.00}} },
+        { 507666784000ns, {{601.00, 274.00}} },
+        { 507669660483ns, {{599.65, 275.68}} },
+        { 507675427000ns, {{582.00, 308.00}} },
+        { 507683740000ns, {{541.00, 404.00}} },
+        { 507686506238ns, {{527.36, 435.95}} },
+        { 507692220000ns, {{487.00, 581.00}} },
+        { 507700707000ns, {{454.00, 792.00}} },
+        { 507703352649ns, {{443.71, 857.77}} },
+        { 507703352649ns, {{443.71, 857.77}} }, // ACTION_UP
     };
-    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
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -4111.8173);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -6388.48877);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 29765.908203);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 28354.796875);
 }
 
+/**
+ * ================== Multiple pointers ============================================================
+ *
+ * Three fingers quickly tap the screen. Since this is a tap, the velocities should be zero.
+ * If the events with POINTER_UP or POINTER_DOWN are not handled correctly (these should not be
+ * part of the fitted data), this can cause large velocity values to be reported instead.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFingerTap) {
+    std::vector<MotionEventEntry> motions = {
+        { 0us,      {{1063, 1128}, {NAN, NAN}, {NAN, NAN}} },
+        { 10800us,  {{1063, 1128}, {682, 1318}, {NAN, NAN}} }, // POINTER_DOWN
+        { 10800us,  {{1063, 1128}, {682, 1318}, {397, 1747}} }, // POINTER_DOWN
+        { 267300us, {{1063, 1128}, {682, 1318}, {397, 1747}} }, // POINTER_UP
+        { 267300us, {{1063, 1128}, {NAN, NAN}, {397, 1747}} }, // POINTER_UP
+        { 272700us, {{1063, 1128}, {NAN, NAN}, {NAN, NAN}} },
+    };
+
+    // Velocity should actually be zero, but we expect 0.016 here instead.
+    // This is close enough to zero, and is likely caused by division by a very small number.
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -0.016);
+    computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -0.016);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 0);
+    computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 0);
+}
+
+/**
+ * ================== Tests for least squares fitting ==============================================
+ *
+ * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy
+ * getEstimator function. In particular:
+ * - inside the function, time gets converted from nanoseconds to seconds
+ *   before being used in the fit.
+ * - any values that are older than 100 ms are being discarded.
+ * - the newest time gets subtracted from all of the other times before being used in the fit.
+ * So these tests have to be designed with those limitations in mind.
+ *
+ * General approach for the tests below:
+ * We only used timestamps in milliseconds, 0 ms, 1 ms, and 2 ms, to be sure that
+ * we are well within the HORIZON range.
+ * When specifying the expected values of the coefficients, we treat the x values as if
+ * they were in ms. Then, to adjust for the time units, the coefficients get progressively
+ * multiplied by powers of 1E3.
+ * For example:
+ * data: t(ms), x
+ *        1 ms, 1
+ *        2 ms, 4
+ *        3 ms, 9
+ * The coefficients are (0, 0, 1).
+ * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2).
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) {
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{1, 1}} }, // 0 s
+        { 1ms, {{1, 1}} }, // 0.001 s
+        { 2ms, {{1, 1}} }, // 0.002 s
+        { 2ms, {{1, 1}} }, // ACTION_UP
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 1
+    // -0.ms, 1
+    computeAndCheckQuadraticEstimate(motions, std::array<float, 3>({1, 0, 0}));
+}
+
+/*
+ * Straight line y = x :: the constant and quadratic coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) {
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{-2, -2}} },
+        { 1ms, {{-1, -1}} },
+        { 2ms, {{-0, -0}} },
+        { 2ms, {{-0, -0}} }, // ACTION_UP
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, -2
+    // -0.001, -1
+    // -0.000,  0
+    computeAndCheckQuadraticEstimate(motions, std::array<float, 3>({0, 1E3, 0}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) {
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{1, 1}} },
+        { 1ms, {{4, 4}} },
+        { 2ms, {{8, 8}} },
+        { 2ms, {{8, 8}} }, // ACTION_UP
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 4
+    // -0.000, 8
+    computeAndCheckQuadraticEstimate(motions, std::array<float, 3>({8, 4.5E3, 0.5E6}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) {
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{1, 1}} },
+        { 1ms, {{4, 4}} },
+        { 2ms, {{9, 9}} },
+        { 2ms, {{9, 9}} }, // ACTION_UP
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 1
+    // -0.001, 4
+    // -0.000, 9
+    computeAndCheckQuadraticEstimate(motions, std::array<float, 3>({9, 6E3, 1E6}));
+}
+
+/*
+ * Parabola :: y = x^2 :: the constant and linear coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) {
+    std::vector<MotionEventEntry> motions = {
+        { 0ms, {{4, 4}} },
+        { 1ms, {{1, 1}} },
+        { 2ms, {{0, 0}} },
+        { 2ms, {{0, 0}} }, // ACTION_UP
+    };
+    // The data used for the fit will be as follows:
+    // time(s), position
+    // -0.002, 4
+    // -0.001, 1
+    // -0.000, 0
+    computeAndCheckQuadraticEstimate(motions, std::array<float, 3>({0, 0E3, 1E6}));
+}
 
 } // namespace android
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
new file mode 100644
index 0000000..6fb149a
--- /dev/null
+++ b/libs/math/OWNERS
@@ -0,0 +1,6 @@
+jaesoo@google.com
+jiyong@google.com
+mathias@google.com
+pawin@google.com
+randolphs@google.com
+romainguy@google.com
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 49ffc8f..9bd3095 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -41,33 +41,11 @@
 // ----------------------------------------------------------------------------
 
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer) {
-    if (!outBuffer || !desc)
-        return BAD_VALUE;
-
-    if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
-        ALOGE("Invalid AHardwareBuffer pixel format %u (%#x))", desc->format, desc->format);
-        return BAD_VALUE;
-    }
+    if (!outBuffer || !desc) return BAD_VALUE;
+    if (!AHardwareBuffer_isValidDescription(desc, /*log=*/true)) return BAD_VALUE;
 
     int format = AHardwareBuffer_convertToPixelFormat(desc->format);
-    if (desc->rfu0 != 0 || desc->rfu1 != 0) {
-        ALOGE("AHardwareBuffer_Desc::rfu fields must be 0");
-        return BAD_VALUE;
-    }
-
-    if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) {
-        ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB format");
-        return BAD_VALUE;
-    }
-
-    if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) &&
-        (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) {
-        ALOGE("AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER "
-              "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER");
-        return BAD_VALUE;
-    }
-
-    uint64_t usage =  AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
+    uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
     sp<GraphicBuffer> gbuffer(new GraphicBuffer(
             desc->width, desc->height, format, desc->layers, usage,
             std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]"));
@@ -115,13 +93,100 @@
     outDesc->rfu1 = 0;
 }
 
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, void** outVirtualAddress,
+        int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+    if (outBytesPerPixel) *outBytesPerPixel = -1;
+    if (outBytesPerStride) *outBytesPerStride = -1;
+
+    if (!buffer) {
+        return BAD_VALUE;
+    }
+
+    if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+                  AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
+        ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+                "AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
+        return BAD_VALUE;
+    }
+
+    usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+    GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+    //Mapper implementations before 3.0 will not return bytes per pixel or
+    //bytes per stride information.
+    if (gbuffer->getBufferMapperVersion() == GraphicBufferMapper::Version::GRALLOC_2) {
+        ALOGE("Mapper versions before 3.0 cannot retrieve bytes per pixel and bytes per stride info");
+        return INVALID_OPERATION;
+    }
+
+    if (gbuffer->getLayerCount() > 1) {
+        ALOGE("Buffer with multiple layers passed to AHardwareBuffer_lock; "
+                "only buffers with one layer are allowed");
+        return INVALID_OPERATION;
+    }
+
+    Rect bounds;
+    if (!rect) {
+        bounds.set(Rect(gbuffer->getWidth(), gbuffer->getHeight()));
+    } else {
+        bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
+    }
+    int32_t bytesPerPixel;
+    int32_t bytesPerStride;
+    int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
+
+    // if hardware returns -1 for bytes per pixel or bytes per stride, we fail
+    // and unlock the buffer
+    if (bytesPerPixel == -1 || bytesPerStride == -1) {
+        gbuffer->unlock();
+        return INVALID_OPERATION;
+    }
+
+    if (outBytesPerPixel) *outBytesPerPixel = bytesPerPixel;
+    if (outBytesPerStride) *outBytesPerStride = bytesPerStride;
+    return result;
+}
+
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, void** outVirtualAddress) {
+                         int32_t fence, const ARect* rect, void** outVirtualAddress) {
+    int32_t bytesPerPixel;
+    int32_t bytesPerStride;
+
     if (!buffer) return BAD_VALUE;
 
     if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
                   AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
         ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+                "AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
+        return BAD_VALUE;
+    }
+
+    usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+    GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+    if (gbuffer->getLayerCount() > 1) {
+        ALOGE("Buffer with multiple layers passed to AHardwareBuffer_lock; "
+                "only buffers with one layer are allowed");
+        return INVALID_OPERATION;
+    }
+
+    Rect bounds;
+    if (!rect) {
+        bounds.set(Rect(gbuffer->getWidth(), gbuffer->getHeight()));
+    } else {
+        bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
+    }
+    return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
+}
+
+int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) {
+    if (!buffer || !outPlanes) return BAD_VALUE;
+
+    if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+                  AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
+        ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
                 " AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
         return BAD_VALUE;
     }
@@ -134,7 +199,33 @@
     } else {
         bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
     }
-    return gBuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence);
+    int format = AHardwareBuffer_convertFromPixelFormat(uint32_t(gBuffer->getPixelFormat()));
+    memset(outPlanes->planes, 0, sizeof(outPlanes->planes));
+    if (AHardwareBuffer_formatIsYuv(format)) {
+      android_ycbcr yuvData;
+      int result = gBuffer->lockAsyncYCbCr(usage, bounds, &yuvData, fence);
+      if (result == 0) {
+        outPlanes->planeCount = 3;
+        outPlanes->planes[0].data = yuvData.y;
+        outPlanes->planes[0].pixelStride = 1;
+        outPlanes->planes[0].rowStride = yuvData.ystride;
+        outPlanes->planes[1].data = yuvData.cb;
+        outPlanes->planes[1].pixelStride = yuvData.chroma_step;
+        outPlanes->planes[1].rowStride = yuvData.cstride;
+        outPlanes->planes[2].data = yuvData.cr;
+        outPlanes->planes[2].pixelStride = yuvData.chroma_step;
+        outPlanes->planes[2].rowStride = yuvData.cstride;
+      } else {
+        outPlanes->planeCount = 0;
+      }
+      return result;
+    } else {
+      const uint32_t pixelStride = AHardwareBuffer_bytesPerPixel(format);
+      outPlanes->planeCount = 1;
+      outPlanes->planes[0].pixelStride = pixelStride;
+      outPlanes->planes[0].rowStride = gBuffer->getStride() * pixelStride;
+      return gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence);
+    }
 }
 
 int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
@@ -274,6 +365,38 @@
     return NO_ERROR;
 }
 
+int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) {
+    if (!desc) return 0;
+    if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0;
+
+    bool supported = false;
+    GraphicBuffer* gBuffer = new GraphicBuffer();
+    status_t err = gBuffer->isSupported(desc->width, desc->height, desc->format, desc->layers,
+                                        desc->usage, &supported);
+
+    if (err == NO_ERROR) {
+        return supported;
+    }
+
+    // function isSupported is not implemented on device or an error occurred during HAL
+    // query.  Make a trial allocation.
+    AHardwareBuffer_Desc trialDesc = *desc;
+    trialDesc.width = 4;
+    trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4;
+    if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) {
+        trialDesc.layers = desc->layers == 6 ? 6 : 12;
+    } else {
+        trialDesc.layers = desc->layers == 1 ? 1 : 2;
+    }
+    AHardwareBuffer* trialBuffer = nullptr;
+    int result = AHardwareBuffer_allocate(&trialDesc, &trialBuffer);
+    if (result == NO_ERROR) {
+        AHardwareBuffer_release(trialBuffer);
+        return 1;
+    }
+    return 0;
+}
+
 
 // ----------------------------------------------------------------------------
 // VNDK functions
@@ -286,6 +409,35 @@
     return gbuffer->handle;
 }
 
+int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
+                                     const native_handle_t* handle, int32_t method,
+                                     AHardwareBuffer** outBuffer) {
+    static_assert(static_cast<int32_t>(AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER) ==
+                  static_cast<int32_t>(GraphicBuffer::TAKE_UNREGISTERED_HANDLE));
+    static_assert(static_cast<int32_t>(AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE) ==
+                  static_cast<int32_t>(GraphicBuffer::CLONE_HANDLE));
+
+    if (!desc || !handle || !outBuffer) return BAD_VALUE;
+    if (!(method == AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER ||
+          method == AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE))
+        return BAD_VALUE;
+    if (desc->rfu0 != 0 || desc->rfu1 != 0) return BAD_VALUE;
+    if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) return BAD_VALUE;
+
+    const int format = AHardwareBuffer_convertToPixelFormat(desc->format);
+    const uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
+    const auto wrapMethod = static_cast<GraphicBuffer::HandleWrapMethod>(method);
+    sp<GraphicBuffer> gbuffer(new GraphicBuffer(handle, wrapMethod, desc->width, desc->height,
+                                                format, desc->layers, usage, desc->stride));
+    status_t err = gbuffer->initCheck();
+    if (err != 0 || gbuffer->handle == 0) return err;
+
+    *outBuffer = AHardwareBuffer_from_GraphicBuffer(gbuffer.get());
+    // Ensure the buffer doesn't get destroyed when the sp<> goes away.
+    AHardwareBuffer_acquire(*outBuffer);
+
+    return NO_ERROR;
+}
 
 // ----------------------------------------------------------------------------
 // Helpers implementation
@@ -293,14 +445,84 @@
 
 namespace android {
 
-// A 1:1 mapping of AHardwaqreBuffer bitmasks to gralloc1 bitmasks.
-struct UsageMaskMapping {
-    uint64_t hardwareBufferMask;
-    uint64_t grallocMask;
-};
+bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log) {
+    if (desc->width == 0 || desc->height == 0 || desc->layers == 0) {
+        ALOGE_IF(log, "Width, height and layers must all be nonzero");
+        return false;
+    }
 
-static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
-    return (mask & bitsToCheck) == bitsToCheck && bitsToCheck;
+    if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
+        ALOGE_IF(log, "Invalid AHardwareBuffer pixel format %u (%#x))",
+                desc->format, desc->format);
+        return false;
+    }
+
+    if (desc->rfu0 != 0 || desc->rfu1 != 0) {
+        ALOGE_IF(log, "AHardwareBuffer_Desc::rfu fields must be 0");
+        return false;
+    }
+
+    if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB) {
+        if (desc->height != 1 || desc->layers != 1) {
+            ALOGE_IF(log, "Height and layers must be 1 for AHARDWAREBUFFER_FORMAT_BLOB");
+            return false;
+        }
+        const uint64_t blobInvalidGpuMask =
+            AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+            AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
+            AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
+            AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
+        if (desc->usage & blobInvalidGpuMask) {
+            ALOGE_IF(log, "Invalid GPU usage flag for AHARDWAREBUFFER_FORMAT_BLOB; "
+                    "only AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER is allowed");
+            return false;
+        }
+        if (desc->usage & AHARDWAREBUFFER_USAGE_VIDEO_ENCODE) {
+            ALOGE_IF(log, "AHARDWAREBUFFER_FORMAT_BLOB cannot be encoded as video");
+            return false;
+        }
+    } else if (AHardwareBuffer_formatIsYuv(desc->format)) {
+        if (desc->layers != 1) {
+            ALOGE_IF(log, "Layers must be 1 for YUV formats.");
+            return false;
+        }
+        const uint64_t yuvInvalidGpuMask =
+            AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
+            AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
+        if (desc->usage & yuvInvalidGpuMask) {
+            ALOGE_IF(log, "Invalid usage flags specified for YUV format; "
+                    "mip-mapping and cube-mapping are not allowed.");
+            return false;
+        }
+    } else {
+        if (desc->usage & AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA) {
+            ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA requires AHARDWAREBUFFER_FORMAT_BLOB");
+            return false;
+        }
+        if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
+            ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER requires AHARDWAREBUFFER_FORMAT_BLOB");
+            return false;
+        }
+    }
+
+    if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) &&
+        (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) {
+        ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER "
+              "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER");
+        return false;
+    }
+
+    if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) {
+        if (desc->width != desc->height) {
+            ALOGE_IF(log, "Cube maps must be square");
+            return false;
+        }
+        if (desc->layers % 6 != 0) {
+            ALOGE_IF(log, "Cube map layers must be a multiple of 6");
+            return false;
+        }
+    }
+    return true;
 }
 
 bool AHardwareBuffer_isValidPixelFormat(uint32_t format) {
@@ -371,6 +593,7 @@
         case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
         case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
         case AHARDWAREBUFFER_FORMAT_S8_UINT:
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
             // VNDK formats only -- unfortunately we can't differentiate from where we're called
         case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
         case AHARDWAREBUFFER_FORMAT_YV12:
@@ -381,7 +604,6 @@
         case AHARDWAREBUFFER_FORMAT_RAW12:
         case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
         case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
-        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
         case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
         case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
@@ -392,6 +614,40 @@
     }
 }
 
+bool AHardwareBuffer_formatIsYuv(uint32_t format) {
+    switch (format) {
+        case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
+        case AHARDWAREBUFFER_FORMAT_YV12:
+        case AHARDWAREBUFFER_FORMAT_Y8:
+        case AHARDWAREBUFFER_FORMAT_Y16:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
+        case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
+        case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+            return true;
+        default:
+            return false;
+    }
+}
+
+uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format) {
+  switch (format) {
+      case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+          return 2;
+      case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+          return 3;
+      case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+      case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+      case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+      case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+          return 4;
+      default:
+          return 0;
+  }
+}
+
 uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) {
     return hal_format;
 }
@@ -416,7 +672,7 @@
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE == (uint64_t)BufferUsage::GPU_TEXTURE,
             "gralloc and AHardwareBuffer flags don't match");
-    static_assert(AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT == (uint64_t)BufferUsage::GPU_RENDER_TARGET,
+    static_assert(AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER == (uint64_t)BufferUsage::GPU_RENDER_TARGET,
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT == (uint64_t)BufferUsage::PROTECTED,
             "gralloc and AHardwareBuffer flags don't match");
@@ -438,11 +694,11 @@
 }
 
 const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer) {
-    return reinterpret_cast<const GraphicBuffer*>(buffer);
+    return GraphicBuffer::fromAHardwareBuffer(buffer);
 }
 
 GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer) {
-    return reinterpret_cast<GraphicBuffer*>(buffer);
+    return GraphicBuffer::fromAHardwareBuffer(buffer);
 }
 
 const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer) {
@@ -454,7 +710,7 @@
 }
 
 AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
-    return reinterpret_cast<AHardwareBuffer*>(buffer);
+    return buffer->toAHardwareBuffer();
 }
 
 } // namespace android
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 765dcd9..8435dac 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -126,12 +126,12 @@
 }
 
 int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
-    static_assert(ADATASPACE_UNKNOWN == HAL_DATASPACE_UNKNOWN);
-    static_assert(ADATASPACE_SCRGB_LINEAR == HAL_DATASPACE_V0_SCRGB_LINEAR);
-    static_assert(ADATASPACE_SRGB == HAL_DATASPACE_V0_SRGB);
-    static_assert(ADATASPACE_SCRGB == HAL_DATASPACE_V0_SCRGB);
-    static_assert(ADATASPACE_DISPLAY_P3 == HAL_DATASPACE_DISPLAY_P3);
-    static_assert(ADATASPACE_BT2020_PQ == HAL_DATASPACE_BT2020_PQ);
+    static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
+    static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR));
+    static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
+    static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
+    static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
+    static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
 
     if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
             !isDataSpaceValid(window, dataSpace)) {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5fbb3b2..27ab482 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -13,13 +13,20 @@
 // limitations under the License.
 
 ndk_headers {
-    name: "libnativewindow_headers",
+    name: "libnativewindow_ndk_headers",
     from: "include/android",
     to: "android",
     srcs: ["include/android/*.h"],
     license: "NOTICE",
 }
 
+// TODO(b/118715870): cleanup header files
+cc_library_headers {
+    name: "libnativewindow_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+}
+
 ndk_library {
     name: "libnativewindow",
     symbol_file: "libnativewindow.map.txt",
@@ -40,13 +47,10 @@
     cflags: [
         "-Wall",
         "-Werror",
+        "-Wno-enum-compare",
         "-Wno-unused-function",
     ],
 
-    cppflags: [
-        "-std=c++1z"
-    ],
-
     version_script: "libnativewindow.map.txt",
 
     srcs: [
@@ -70,6 +74,7 @@
 
     header_libs: [
         "libnativebase_headers",
+        "libnativewindow_headers",
     ],
 
     // headers we include in our public headers
diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
index 71f5634..ddfd1d1 100644
--- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
@@ -28,13 +28,24 @@
 #include <stdint.h>
 
 struct AHardwareBuffer;
+struct AHardwareBuffer_Desc;
 struct ANativeWindowBuffer;
 
 namespace android {
 
+// Validates whether the passed description does not have conflicting
+// parameters. Note: this does not verify any platform-specific contraints.
+bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log);
+
 // whether this AHardwareBuffer format is valid
 bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);
 
+// whether this is a YUV type format
+bool AHardwareBuffer_formatIsYuv(uint32_t format);
+
+// number of bytes per pixel or 0 if unknown or multi-planar
+uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format);
+
 // convert AHardwareBuffer format to HAL format (note: this is a no-op)
 uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
 
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 3ac1c58..2899bcf 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -75,7 +75,7 @@
      * scRGB:
      *
      * The red, green, and blue components are stored in extended sRGB space,
-     * but are linear, not gamma-encoded.
+     * and gamma-encoded using the SRGB transfer function.
      * The RGB primaries and the white point are the same as BT.709.
      *
      * The values are floating point.
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 78cec41..da959e3 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -16,6 +16,30 @@
 
 /**
  * @file hardware_buffer.h
+ * @brief API for native hardware buffers.
+ */
+/**
+ * @defgroup AHardwareBuffer Native Hardware Buffer
+ *
+ * AHardwareBuffer objects represent chunks of memory that can be
+ * accessed by various hardware components in the system. It can be
+ * easily converted to the Java counterpart
+ * android.hardware.HardwareBuffer and passed between processes using
+ * Binder. All operations involving AHardwareBuffer and HardwareBuffer
+ * are zero-copy, i.e., passing AHardwareBuffer to another process
+ * creates a shared view of the same region of memory.
+ *
+ * AHardwareBuffers can be bound to EGL/OpenGL and Vulkan primitives.
+ * For EGL, use the extension function eglGetNativeClientBufferANDROID
+ * to obtain an EGLClientBuffer and pass it directly to
+ * eglCreateImageKHR. Refer to the EGL extensions
+ * EGL_ANDROID_get_native_client_buffer and
+ * EGL_ANDROID_image_native_buffer for more information. In Vulkan,
+ * the contents of the AHardwareBuffer can be accessed as external
+ * memory. See the VK_ANDROID_external_memory_android_hardware_buffer
+ * extension for details.
+ *
+ * @{
  */
 
 #ifndef ANDROID_HARDWARE_BUFFER_H
@@ -32,7 +56,7 @@
 /**
  * Buffer pixel formats.
  */
-enum {
+enum AHardwareBuffer_Format {
     /**
      * Corresponding formats:
      *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
@@ -78,8 +102,10 @@
     AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM        = 0x2b,
 
     /**
-     * An opaque binary blob format that must have height 1, with width equal to
-     * the buffer size in bytes.
+     * Opaque binary blob format.
+     * Must have height 1 and one layer, with width equal to the buffer
+     * size in bytes. Corresponds to Vulkan buffers and OpenGL buffer
+     * objects. Can be bound to the latter using GL_EXT_external_buffer.
      */
     AHARDWAREBUFFER_FORMAT_BLOB                     = 0x21,
 
@@ -124,51 +150,118 @@
      *   OpenGL ES: GL_STENCIL_INDEX8
      */
     AHARDWAREBUFFER_FORMAT_S8_UINT                  = 0x35,
+
+    /**
+     * YUV 420 888 format.
+     * Must have an even width and height. Can be accessed in OpenGL
+     * shaders through an external sampler. Does not support mip-maps
+     * cube-maps or multi-layered textures.
+     */
+    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
 };
 
 /**
  * Buffer usage flags, specifying how the buffer will be accessed.
  */
-enum {
-    /// The buffer will never be read by the CPU.
+enum AHardwareBuffer_UsageFlags {
+    /// The buffer will never be locked for direct CPU reads using the
+    /// AHardwareBuffer_lock() function. Note that reading the buffer
+    /// using OpenGL or Vulkan functions or memory mappings is still
+    /// allowed.
     AHARDWAREBUFFER_USAGE_CPU_READ_NEVER        = 0UL,
-    /// The buffer will sometimes be read by the CPU.
+    /// The buffer will sometimes be locked for direct CPU reads using
+    /// the AHardwareBuffer_lock() function. Note that reading the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_READ_RARELY       = 2UL,
-    /// The buffer will often be read by the CPU.
+    /// The buffer will often be locked for direct CPU reads using
+    /// the AHardwareBuffer_lock() function. Note that reading the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN        = 3UL,
     /// CPU read value mask.
     AHARDWAREBUFFER_USAGE_CPU_READ_MASK         = 0xFUL,
 
-    /// The buffer will never be written by the CPU.
+    /// The buffer will never be locked for direct CPU writes using the
+    /// AHardwareBuffer_lock() function. Note that writing the buffer
+    /// using OpenGL or Vulkan functions or memory mappings is still
+    /// allowed.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER       = 0UL << 4,
-    /// The buffer will sometimes be written to by the CPU.
+    /// The buffer will sometimes be locked for direct CPU writes using
+    /// the AHardwareBuffer_lock() function. Note that writing the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY      = 2UL << 4,
-    /// The buffer will often be written to by the CPU.
+    /// The buffer will often be locked for direct CPU writes using
+    /// the AHardwareBuffer_lock() function. Note that writing the
+    /// buffer using OpenGL or Vulkan functions or memory mappings
+    /// does not require the presence of this flag.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN       = 3UL << 4,
     /// CPU write value mask.
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
 
     /// The buffer will be read from by the GPU as a texture.
     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
+    /// The buffer will be written to by the GPU as a framebuffer attachment.
+    AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER        = 1UL << 9,
     /**
-     * The buffer will be written to by the GPU as a framebuffer attachment.
-     * Note that the name of this flag is somewhat misleading: it does not imply
-     * that the buffer contains a color format. A buffer with depth or stencil
-     * format that will be used as a framebuffer attachment should also have
-     * this flag.
+     * The buffer will be written to by the GPU as a framebuffer
+     * attachment.
+     *
+     * Note that the name of this flag is somewhat misleading: it does
+     * not imply that the buffer contains a color format. A buffer with
+     * depth or stencil format that will be used as a framebuffer
+     * attachment should also have this flag. Use the equivalent flag
+     * AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion.
      */
-    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = 1UL << 9,
-    /// The buffer must not be used outside of a protected hardware path.
+    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+    /**
+     * The buffer will be used as a composer HAL overlay layer.
+     *
+     * This flag is currently only needed when using ASurfaceTransaction_setBuffer
+     * to set a buffer. In all other cases, the framework adds this flag
+     * internally to buffers that could be presented in a composer overlay.
+     * ASurfaceTransaction_setBuffer is special because it uses buffers allocated
+     * directly through AHardwareBuffer_allocate instead of buffers allocated
+     * by the framework.
+     */
+    AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY       = 1ULL << 11,
+    /**
+     * The buffer is protected from direct CPU access or being read by
+     * non-secure hardware, such as video encoders.
+     *
+     * This flag is incompatible with CPU read and write flags. It is
+     * mainly used when handling DRM video. Refer to the EGL extension
+     * EGL_EXT_protected_content and GL extension
+     * GL_EXT_protected_textures for more information on how these
+     * buffers are expected to behave.
+     */
     AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
     /// The buffer will be read by a hardware video encoder.
     AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
-    /// The buffer will be used for direct writes from sensors.
+    /**
+     * The buffer will be used for direct writes from sensors.
+     * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+     */
     AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
-    /// The buffer will be used as a shader storage or uniform buffer object.
+    /**
+     * The buffer will be used as a shader storage or uniform buffer object.
+     * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+     */
     AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
-    /// The buffer will be used as a cube map texture.
+    /**
+     * The buffer will be used as a cube map texture.
+     * When this flag is present, the buffer must have a layer count
+     * that is a multiple of 6. Note that buffers with this flag must be
+     * bound to OpenGL textures using the extension
+     * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
+     */
     AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
-    /// The buffer contains a complete mipmap hierarchy.
+    /**
+     * The buffer contains a complete mipmap hierarchy.
+     * Note that buffers with this flag must be bound to OpenGL textures using
+     * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
+     */
     AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
 
     AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
@@ -194,97 +287,185 @@
 };
 
 /**
- * Buffer description. Used for allocating new buffers and querying parameters
- * of existing ones.
+ * Buffer description. Used for allocating new buffers and querying
+ * parameters of existing ones.
  */
 typedef struct AHardwareBuffer_Desc {
     uint32_t    width;      ///< Width in pixels.
     uint32_t    height;     ///< Height in pixels.
-    uint32_t    layers;     ///< Number of images in an image array.
-    uint32_t    format;     ///< One of AHARDWAREBUFFER_FORMAT_*
-    uint64_t    usage;      ///< Combination of AHARDWAREBUFFER_USAGE_*
+    /**
+     * Number of images in an image array. AHardwareBuffers with one
+     * layer correspond to regular 2D textures. AHardwareBuffers with
+     * more than layer correspond to texture arrays. If the layer count
+     * is a multiple of 6 and the usage flag
+     * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is
+     * a cube map or a cube map array.
+     */
+    uint32_t    layers;
+    uint32_t    format;     ///< One of AHardwareBuffer_Format.
+    uint64_t    usage;      ///< Combination of AHardwareBuffer_UsageFlags.
     uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
     uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
     uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
-typedef struct AHardwareBuffer AHardwareBuffer;
+/**
+ * Holds data for a single image plane.
+ */
+typedef struct AHardwareBuffer_Plane {
+    void*       data;        ///< Points to first byte in plane
+    uint32_t    pixelStride; ///< Distance in bytes from the color channel of one pixel to the next
+    uint32_t    rowStride;   ///< Distance in bytes from the first value of one row of the image to
+                             ///  the first value of the next row.
+} AHardwareBuffer_Plane;
 
 /**
- * Allocates a buffer that backs an AHardwareBuffer using the passed
- * AHardwareBuffer_Desc.
+ * Holds all image planes that contain the pixel data.
+ */
+typedef struct AHardwareBuffer_Planes {
+    uint32_t               planeCount; ///< Number of distinct planes
+    AHardwareBuffer_Plane  planes[4];     ///< Array of image planes
+} AHardwareBuffer_Planes;
+
+/**
+ * Opaque handle for a native hardware buffer.
+ */
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+#if __ANDROID_API__ >= 26
+
+/**
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
  *
  * \return 0 on success, or an error number of the allocation fails for
  * any reason. The returned buffer has a reference count of 1.
  */
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
-        AHardwareBuffer** outBuffer);
+        AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
 /**
- * Acquire a reference on the given AHardwareBuffer object.  This prevents the
- * object from being deleted until the last reference is removed.
+ * Acquire a reference on the given AHardwareBuffer object.
+ *
+ * This prevents the object from being deleted until the last reference
+ * is removed.
  */
-void AHardwareBuffer_acquire(AHardwareBuffer* buffer);
+void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with
- * AHardwareBuffer_acquire().
+ * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
  */
-void AHardwareBuffer_release(AHardwareBuffer* buffer);
+void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Return a description of the AHardwareBuffer in the passed
  * AHardwareBuffer_Desc struct.
  */
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
-        AHardwareBuffer_Desc* outDesc);
+        AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
 
 /**
- * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
- * passed.  This call may block if the hardware needs to finish rendering or if
- * CPU caches need to be synchronized, or possibly for other implementation-
- * specific reasons.  If fence is not negative, then it specifies a fence file
- * descriptor that will be signaled when the buffer is locked, otherwise the
- * caller will block until the buffer is available.
+ * Lock the AHardwareBuffer for direct CPU access.
  *
- * If \a rect is not NULL, the caller promises to modify only data in the area
- * specified by rect. If rect is NULL, the caller may modify the contents of the
- * entire buffer.
+ * This function can lock the buffer for either reading or writing.
+ * It may block if the hardware needs to finish rendering, if CPU caches
+ * need to be synchronized, or possibly for other implementation-
+ * specific reasons.
  *
- * The content of the buffer outside of the specified rect is NOT modified
- * by this call.
+ * The passed AHardwareBuffer must have one layer, otherwise the call
+ * will fail.
  *
- * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
- * then outVirtualAddress is filled with the address of the buffer in virtual
+ * If \a fence is not negative, it specifies a fence file descriptor on
+ * which to wait before locking the buffer. If it's negative, the caller
+ * is responsible for ensuring that writes to the buffer have completed
+ * before calling this function.  Using this parameter is more efficient
+ * than waiting on the fence and then calling this function.
+ *
+ * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*.
+ * If set, then outVirtualAddress is filled with the address of the
+ * buffer in virtual memory. The flags must also be compatible with
+ * usage flags specified at buffer creation: if a read flag is passed,
+ * the buffer must have been created with
+ * AHARDWAREBUFFER_USAGE_CPU_READ_RARELY or
+ * AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN. If a write flag is passed, it
+ * must have been created with AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY or
+ * AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN.
+ *
+ * If \a rect is not NULL, the caller promises to modify only data in
+ * the area specified by rect. If rect is NULL, the caller may modify
+ * the contents of the entire buffer. The content of the buffer outside
+ * of the specified rect is NOT modified by this call.
+ *
+ * It is legal for several different threads to lock a buffer for read
+ * access; none of the threads are blocked.
+ *
+ * Locking a buffer simultaneously for write or read/write is undefined,
+ * but will neither terminate the process nor block the caller.
+ * AHardwareBuffer_lock may return an error or leave the buffer's
+ * content in an indeterminate state.
+ *
+ * If the buffer has AHARDWAREBUFFER_FORMAT_BLOB, it is legal lock it
+ * for reading and writing in multiple threads and/or processes
+ * simultaneously, and the contents of the buffer behave like shared
  * memory.
  *
- * THREADING CONSIDERATIONS:
- *
- * It is legal for several different threads to lock a buffer for read access;
- * none of the threads are blocked.
- *
- * Locking a buffer simultaneously for write or read/write is undefined, but
- * will neither terminate the process nor block the caller; AHardwareBuffer_lock
- * may return an error or leave the buffer's content into an indeterminate
- * state.
- *
- * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage
- * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
- * number of the lock fails for any reason.
+ * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
+ * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
+ * has more than one layer. Error number if the lock fails for any other
+ * reason.
  */
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, void** outVirtualAddress);
+        int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
 
 /**
- * Unlock the AHardwareBuffer; must be called after all changes to the buffer
- * are completed by the caller. If fence is not NULL then it will be set to a
- * file descriptor that is signaled when all pending work on the buffer is
- * completed. The caller is responsible for closing the fence when it is no
- * longer needed.
+ * Lock a potentially multi-planar AHardwareBuffer for direct CPU access.
  *
- * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
- * number if the unlock fails for any reason.
+ * This function is similar to AHardwareBuffer_lock, but can lock multi-planar
+ * formats. The locked planes are returned in the \a outPlanes argument. Note,
+ * that multi-planar should not be confused with multi-layer images, which this
+ * locking function does not support.
+ *
+ * YUV formats are always represented by three separate planes of data, one for
+ * each color plane. The order of planes in the array is guaranteed such that
+ * plane #0 is always Y, plane #1 is always U (Cb), and plane #2 is always V
+ * (Cr). All other formats are represented by a single plane.
+ *
+ * Additional information always accompanies the buffers, describing the row
+ * stride and the pixel stride for each plane.
+ *
+ * In case the buffer cannot be locked, \a outPlanes will contain zero planes.
+ *
+ * See the AHardwareBuffer_lock documentation for all other locking semantics.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
+ * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
+ * has more than one layer. Error number if the lock fails for any other
+ * reason.
  */
-int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence);
+int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) __INTRODUCED_IN(29);
+
+/**
+ * Unlock the AHardwareBuffer from direct CPU access.
+ *
+ * Must be called after all changes to the buffer are completed by the
+ * caller.  If \a fence is NULL, the function will block until all work
+ * is completed.  Otherwise, \a fence will be set either to a valid file
+ * descriptor or to -1.  The file descriptor will become signaled once
+ * the unlocking is complete and buffer contents are updated.
+ * The caller is responsible for closing the file descriptor once it's
+ * no longer needed.  The value -1 indicates that unlocking has already
+ * completed before the function returned and no further operations are
+ * necessary.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
+ * the unlock fails for any reason.
+ */
+int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);
 
 /**
  * Send the AHardwareBuffer to an AF_UNIX socket.
@@ -292,16 +473,55 @@
  * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
  * number if the operation fails for any reason.
  */
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);
 
 /**
- * Receive the AHardwareBuffer from an AF_UNIX socket.
+ * Receive an AHardwareBuffer from an AF_UNIX socket.
  *
  * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
  * number if the operation fails for any reason.
  */
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
+
+#endif // __ANDROID_API__ >= 26
+
+#if __ANDROID_API__ >= 29
+
+/**
+ * Test whether the given format and usage flag combination is
+ * allocatable.
+ *
+ * If this function returns true, it means that a buffer with the given
+ * description can be allocated on this implementation, unless resource
+ * exhaustion occurs. If this function returns false, it means that the
+ * allocation of the given description will never succeed.
+ *
+ * The return value of this function may depend on all fields in the
+ * description, except stride, which is always ignored. For example,
+ * some implementations have implementation-defined limits on texture
+ * size and layer count.
+ *
+ * \return 1 if the format and usage flag combination is allocatable,
+ *     0 otherwise.
+ */
+int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);
+
+/**
+ * Lock an AHardwareBuffer for direct CPU access.
+ *
+ * This function is the same as the above lock function, but passes back
+ * additional information about the bytes per pixel and the bytes per stride
+ * of the locked buffer.  If the bytes per pixel or bytes per stride are unknown
+ * or variable, or if the underlying mapper implementation does not support returning
+ * additional information, then this call will fail with INVALID_OPERATION
+ */
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
+        int32_t fence, const ARect* rect, void** outVirtualAddress,
+        int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29);
+#endif // __ANDROID_API__ >= 29
 
 __END_DECLS
 
 #endif // ANDROID_HARDWARE_BUFFER_H
+
+/** @} */
diff --git a/libs/nativewindow/include/android/hdr_metadata.h b/libs/nativewindow/include/android/hdr_metadata.h
new file mode 100644
index 0000000..88772a9
--- /dev/null
+++ b/libs/nativewindow/include/android/hdr_metadata.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file hdr_metadata.h
+ */
+
+#ifndef ANDROID_HDR_METADATA_H
+#define ANDROID_HDR_METADATA_H
+
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * These structures are used to define the display's capabilities for HDR content.
+ * They can be used to better tone map content to user's display.
+ */
+
+/**
+ * HDR metadata standards that are supported by Android.
+ */
+enum AHdrMetadataType : uint32_t {
+    HDR10_SMPTE2086 = 1,
+    HDR10_CTA861_3 = 2,
+    HDR10PLUS_SEI = 3,
+};
+
+/**
+ * Color is defined in CIE XYZ coordinates.
+ */
+struct AColor_xy {
+    float x;
+    float y;
+};
+
+/**
+ * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
+ */
+struct AHdrMetadata_smpte2086 {
+    struct AColor_xy displayPrimaryRed;
+    struct AColor_xy displayPrimaryGreen;
+    struct AColor_xy displayPrimaryBlue;
+    struct AColor_xy whitePoint;
+    float maxLuminance;
+    float minLuminance;
+};
+
+/**
+ * CTA 861.3 "HDR Static Metadata Extension" static metadata
+ */
+struct AHdrMetadata_cta861_3 {
+    float maxContentLightLevel;
+    float maxFrameAverageLightLevel;
+};
+
+__END_DECLS
+
+#endif // ANDROID_HDR_METADATA_H
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index d5e5e9d..6730596 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -15,7 +15,13 @@
  */
 
 /**
- * @addtogroup NativeActivity Native Activity
+ * @defgroup ANativeWindow Native Window
+ *
+ * ANativeWindow represents the producer end of an image queue.
+ * It is the C counterpart of the android.view.Surface object in Java,
+ * and can be converted both ways. Depending on the consumer, images
+ * submitted to ANativeWindow can be shown on the display or sent to
+ * other consumers, such as video encoders.
  * @{
  */
 
@@ -41,7 +47,7 @@
  * Legacy window pixel format names, kept for backwards compatibility.
  * New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
  */
-enum {
+enum ANativeWindow_LegacyFormat {
     // NOTE: these values must match the values from graphics/common/x.x/types.hal
 
     /** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
@@ -95,7 +101,7 @@
     /// memory. This may be >= width.
     int32_t stride;
 
-    /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+    /// The format of the buffer. One of AHardwareBuffer_Format.
     int32_t format;
 
     /// The actual bits.
@@ -151,7 +157,7 @@
  *
  * \param width width of the buffers in pixels.
  * \param height height of the buffers in pixels.
- * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \param format one of the AHardwareBuffer_Format constants.
  * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
@@ -178,7 +184,7 @@
  */
 int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
+#if __ANDROID_API__ >= 26
 
 /**
  * Set a transform that will be applied to future buffers posted to the window.
@@ -186,11 +192,11 @@
  * \param transform combination of {@link ANativeWindowTransform} flags
  * \return 0 for success, or -EINVAL if \p transform is invalid
  */
-int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform);
+int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform) __INTRODUCED_IN(26);
 
-#endif // __ANDROID_API__ >= __ANDROID_API_O__
+#endif // __ANDROID_API__ >= 26
 
-#if __ANDROID_API__ >= __ANDROID_API_P__
+#if __ANDROID_API__ >= 28
 
 /**
  * All buffers queued after this call will be associated with the dataSpace
@@ -206,16 +212,16 @@
  * \return 0 for success, -EINVAL if window is invalid or the dataspace is not
  * supported.
  */
-int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace);
+int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) __INTRODUCED_IN(28);
 
 /**
  * Get the dataspace of the buffers in window.
  * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if
  * dataspace is unknown, or -EINVAL if window is invalid.
  */
-int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window);
+int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN(28);
 
-#endif // __ANDROID_API__ >= __ANDROID_API_P__
+#endif // __ANDROID_API__ >= 28
 
 #ifdef __cplusplus
 };
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 197f73f..61590e0 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -202,7 +202,7 @@
  * ANativeWindow.
  */
 enum {
-// clang-format off
+    // clang-format off
     NATIVE_WINDOW_SET_USAGE                     =  0,   /* deprecated */
     NATIVE_WINDOW_CONNECT                       =  1,   /* deprecated */
     NATIVE_WINDOW_DISCONNECT                    =  2,   /* deprecated */
@@ -237,7 +237,8 @@
     NATIVE_WINDOW_GET_CONSUMER_USAGE64          = 31,
     NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
     NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
-// clang-format on
+    NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
+    // clang-format on
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -748,6 +749,27 @@
 }
 
 /*
+ * native_window_set_buffers_hdr10_plus_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the
+ * HDR10+ dynamic metadata specified.
+ *
+ * metadata specifies additional dynamic information about the
+ * contents of the buffer that may affect how it is displayed.  When
+ * it is nullptr, it means no such information is available.  No
+ * HDR10+ dynamic emtadata is associated with the buffers by default.
+ *
+ * Parameter "size" refers to the length of the metadata blob pointed to
+ * by parameter "data".  The metadata blob will adhere to the HDR10+ SEI
+ * message standard.
+ */
+static inline int native_window_set_buffers_hdr10_plus_metadata(struct ANativeWindow* window,
+                                                           const size_t size,
+                                                           const uint8_t* metadata) {
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA, size,
+                           metadata);
+}
+
+/*
  * native_window_set_buffers_transform(..., int transform)
  * All buffers queued after this call will be displayed transformed according
  * to the transform parameter specified.
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 7a4b31f..3392d7f 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -26,6 +26,28 @@
 
 const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
 
+enum CreateFromHandleMethod {
+    // enum values chosen to match internal GraphicBuffer::HandleWrapMethod
+    AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER = 2,
+    AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE = 3,
+};
+
+/**
+ * Create a AHardwareBuffer from a native handle.
+ *
+ * This function wraps a native handle in a AHardwareBuffer suitable for use by applications or
+ * other parts of the system. The contents of desc will be returned by AHardwareBuffer_describe().
+ *
+ * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER, the handle is assumed to be
+ * unregistered, and it will be registered/imported before being wrapped in the AHardwareBuffer.
+ * If successful, the AHardwareBuffer will own the handle.
+ *
+ * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, the handle will be cloned and the
+ * clone registered. The AHardwareBuffer will own the cloned handle but not the original.
+ */
+int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
+                                     const native_handle_t* handle, int32_t method,
+                                     AHardwareBuffer** outBuffer);
 
 /**
  * Buffer pixel formats.
@@ -51,8 +73,6 @@
     AHARDWAREBUFFER_FORMAT_RAW_OPAQUE               = 0x24,
     /* same as HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED */
     AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED   = 0x22,
-    /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */
-    AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420             = 0x23,
     /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */
     AHARDWAREBUFFER_FORMAT_YCbCr_422_SP             = 0x10,
     /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index d2ba971..bad8b11 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -2,9 +2,13 @@
   global:
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
+    AHardwareBuffer_createFromHandle; # vndk
     AHardwareBuffer_describe;
     AHardwareBuffer_getNativeHandle; # vndk
+    AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock;
+    AHardwareBuffer_lockAndGetInfo; # introduced=29
+    AHardwareBuffer_lockPlanes; # introduced=29
     AHardwareBuffer_recvHandleFromUnixSocket;
     AHardwareBuffer_release;
     AHardwareBuffer_sendHandleToUnixSocket;
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
new file mode 100644
index 0000000..36211ca
--- /dev/null
+++ b/libs/renderengine/Android.bp
@@ -0,0 +1,98 @@
+cc_defaults {
+    name: "renderengine_defaults",
+    cflags: [
+        "-DLOG_TAG=\"RenderEngine\"",
+        "-Wall",
+        "-Werror",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
+
+cc_defaults {
+    name: "librenderengine_defaults",
+    defaults: ["renderengine_defaults"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
+        "libgui",
+        "liblog",
+        "libnativewindow",
+        "libsync",
+        "libui",
+        "libutils",
+    ],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+}
+
+filegroup {
+    name: "librenderengine_sources",
+    srcs: [
+        "Description.cpp",
+        "Mesh.cpp",
+        "RenderEngine.cpp",
+        "Texture.cpp",
+    ],
+}
+
+filegroup {
+    name: "librenderengine_gl_sources",
+    srcs: [
+        "gl/GLESRenderEngine.cpp",
+        "gl/GLExtensions.cpp",
+        "gl/GLFramebuffer.cpp",
+        "gl/GLImage.cpp",
+        "gl/Program.cpp",
+        "gl/ProgramCache.cpp",
+    ],
+}
+
+cc_library_static {
+    name: "librenderengine",
+    defaults: ["librenderengine_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    double_loadable: true,
+    clang: true,
+    cflags: [
+        "-fvisibility=hidden",
+        "-Werror=format",
+    ],
+    cppflags: [
+        "-fwhole-program-vtables", // requires ThinLTO
+    ],
+    srcs: [
+        ":librenderengine_sources",
+        ":librenderengine_gl_sources",
+    ],
+    lto: {
+        thin: true,
+    },
+}
+
+cc_library_static {
+    name: "librenderengine_mocks",
+    defaults: ["librenderengine_defaults"],
+    srcs: [
+        "mock/Framebuffer.cpp",
+        "mock/Image.cpp",
+        "mock/RenderEngine.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+}
diff --git a/libs/renderengine/Description.cpp b/libs/renderengine/Description.cpp
new file mode 100644
index 0000000..b9cea10
--- /dev/null
+++ b/libs/renderengine/Description.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 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 <renderengine/private/Description.h>
+
+#include <stdint.h>
+
+#include <utils/TypeHelpers.h>
+
+namespace android {
+namespace renderengine {
+
+Description::TransferFunction Description::dataSpaceToTransferFunction(ui::Dataspace dataSpace) {
+    ui::Dataspace transfer = static_cast<ui::Dataspace>(dataSpace & ui::Dataspace::TRANSFER_MASK);
+    switch (transfer) {
+        case ui::Dataspace::TRANSFER_ST2084:
+            return Description::TransferFunction::ST2084;
+        case ui::Dataspace::TRANSFER_HLG:
+            return Description::TransferFunction::HLG;
+        case ui::Dataspace::TRANSFER_LINEAR:
+            return Description::TransferFunction::LINEAR;
+        default:
+            return Description::TransferFunction::SRGB;
+    }
+}
+
+bool Description::hasInputTransformMatrix() const {
+    const mat4 identity;
+    return inputTransformMatrix != identity;
+}
+
+bool Description::hasOutputTransformMatrix() const {
+    const mat4 identity;
+    return outputTransformMatrix != identity;
+}
+
+bool Description::hasColorMatrix() const {
+    const mat4 identity;
+    return colorMatrix != identity;
+}
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/Mesh.cpp b/libs/renderengine/Mesh.cpp
new file mode 100644
index 0000000..f5387f2
--- /dev/null
+++ b/libs/renderengine/Mesh.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2013 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 <renderengine/Mesh.h>
+
+#include <utils/Log.h>
+
+namespace android {
+namespace renderengine {
+
+Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
+      : mVertexCount(vertexCount),
+        mVertexSize(vertexSize),
+        mTexCoordsSize(texCoordSize),
+        mPrimitive(primitive) {
+    if (vertexCount == 0) {
+        mVertices.resize(1);
+        mVertices[0] = 0.0f;
+        mStride = 0;
+        return;
+    }
+
+    const size_t CROP_COORD_SIZE = 2;
+    size_t stride = vertexSize + texCoordSize + CROP_COORD_SIZE;
+    size_t remainder = (stride * vertexCount) / vertexCount;
+    // Since all of the input parameters are unsigned, if stride is less than
+    // either vertexSize or texCoordSize, it must have overflowed. remainder
+    // will be equal to stride as long as stride * vertexCount doesn't overflow.
+    if ((stride < vertexSize) || (remainder != stride)) {
+        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize,
+              CROP_COORD_SIZE);
+        mVertices.resize(1);
+        mVertices[0] = 0.0f;
+        mVertexCount = 0;
+        mVertexSize = 0;
+        mTexCoordsSize = 0;
+        mStride = 0;
+        return;
+    }
+
+    mVertices.resize(stride * vertexCount);
+    mStride = stride;
+}
+
+Mesh::Primitive Mesh::getPrimitive() const {
+    return mPrimitive;
+}
+
+float const* Mesh::getPositions() const {
+    return mVertices.data();
+}
+float* Mesh::getPositions() {
+    return mVertices.data();
+}
+
+float const* Mesh::getTexCoords() const {
+    return mVertices.data() + mVertexSize;
+}
+float* Mesh::getTexCoords() {
+    return mVertices.data() + mVertexSize;
+}
+
+float const* Mesh::getCropCoords() const {
+    return mVertices.data() + mVertexSize + mTexCoordsSize;
+}
+float* Mesh::getCropCoords() {
+    return mVertices.data() + mVertexSize + mTexCoordsSize;
+}
+
+size_t Mesh::getVertexCount() const {
+    return mVertexCount;
+}
+
+size_t Mesh::getVertexSize() const {
+    return mVertexSize;
+}
+
+size_t Mesh::getTexCoordsSize() const {
+    return mTexCoordsSize;
+}
+
+size_t Mesh::getByteStride() const {
+    return mStride * sizeof(float);
+}
+
+size_t Mesh::getStride() const {
+    return mStride;
+}
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
new file mode 100644
index 0000000..c00fbba
--- /dev/null
+++ b/libs/renderengine/OWNERS
@@ -0,0 +1,2 @@
+lpy@google.com
+stoza@google.com
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
new file mode 100644
index 0000000..166c267
--- /dev/null
+++ b/libs/renderengine/RenderEngine.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 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 <renderengine/RenderEngine.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <private/gui/SyncFeatures.h>
+#include "gl/GLESRenderEngine.h"
+
+namespace android {
+namespace renderengine {
+
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags,
+                                                         uint32_t imageCacheSize) {
+    char prop[PROPERTY_VALUE_MAX];
+    property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
+    if (strcmp(prop, "gles") == 0) {
+        ALOGD("RenderEngine GLES Backend");
+        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
+    }
+    ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
+    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
+}
+
+RenderEngine::~RenderEngine() = default;
+
+namespace impl {
+
+RenderEngine::RenderEngine(uint32_t featureFlags) : mFeatureFlags(featureFlags) {}
+
+RenderEngine::~RenderEngine() = default;
+
+bool RenderEngine::useNativeFenceSync() const {
+    return SyncFeatures::getInstance().useNativeFenceSync();
+}
+
+bool RenderEngine::useWaitSync() const {
+    return SyncFeatures::getInstance().useWaitSync();
+}
+
+} // namespace impl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
new file mode 100644
index 0000000..995dba1
--- /dev/null
+++ b/libs/renderengine/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "librenderengine_test"
+    }
+  ]
+}
diff --git a/libs/renderengine/Texture.cpp b/libs/renderengine/Texture.cpp
new file mode 100644
index 0000000..154cde8
--- /dev/null
+++ b/libs/renderengine/Texture.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2013 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 <renderengine/Texture.h>
+
+namespace android {
+namespace renderengine {
+
+Texture::Texture()
+      : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {}
+
+Texture::Texture(Target textureTarget, uint32_t textureName)
+      : mTextureName(textureName),
+        mTextureTarget(textureTarget),
+        mWidth(0),
+        mHeight(0),
+        mFiltering(false) {}
+
+void Texture::init(Target textureTarget, uint32_t textureName) {
+    mTextureName = textureName;
+    mTextureTarget = textureTarget;
+}
+
+Texture::~Texture() {}
+
+void Texture::setMatrix(float const* matrix) {
+    mTextureMatrix = mat4(matrix);
+}
+
+void Texture::setFiltering(bool enabled) {
+    mFiltering = enabled;
+}
+
+void Texture::setDimensions(size_t width, size_t height) {
+    mWidth = width;
+    mHeight = height;
+}
+
+uint32_t Texture::getTextureName() const {
+    return mTextureName;
+}
+
+uint32_t Texture::getTextureTarget() const {
+    return mTextureTarget;
+}
+
+const mat4& Texture::getMatrix() const {
+    return mTextureMatrix;
+}
+
+bool Texture::getFiltering() const {
+    return mFiltering;
+}
+
+size_t Texture::getWidth() const {
+    return mWidth;
+}
+
+size_t Texture::getHeight() const {
+    return mHeight;
+}
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
new file mode 100644
index 0000000..46a8e9e
--- /dev/null
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -0,0 +1,1499 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GLESRenderEngine.h"
+
+#include <math.h>
+#include <fstream>
+#include <sstream>
+#include <unordered_set>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/Texture.h>
+#include <renderengine/private/Description.h>
+#include <sync/sync.h>
+#include <ui/ColorSpace.h>
+#include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <utils/KeyedVector.h>
+#include <utils/Trace.h>
+#include "GLExtensions.h"
+#include "GLFramebuffer.h"
+#include "GLImage.h"
+#include "Program.h"
+#include "ProgramCache.h"
+
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
+bool checkGlError(const char* op, int lineNumber) {
+    bool errorFound = false;
+    GLint error = glGetError();
+    while (error != GL_NO_ERROR) {
+        errorFound = true;
+        error = glGetError();
+        ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error);
+    }
+    return errorFound;
+}
+
+static constexpr bool outputDebugPPMs = false;
+
+void writePPM(const char* basename, GLuint width, GLuint height) {
+    ALOGV("writePPM #%s: %d x %d", basename, width, height);
+
+    std::vector<GLubyte> pixels(width * height * 4);
+    std::vector<GLubyte> outBuffer(width * height * 3);
+
+    // TODO(courtneygo): We can now have float formats, need
+    // to remove this code or update to support.
+    // Make returned pixels fit in uint32_t, one byte per component
+    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+    if (checkGlError(__FUNCTION__, __LINE__)) {
+        return;
+    }
+
+    std::string filename(basename);
+    filename.append(".ppm");
+    std::ofstream file(filename.c_str(), std::ios::binary);
+    if (!file.is_open()) {
+        ALOGE("Unable to open file: %s", filename.c_str());
+        ALOGE("You may need to do: \"adb shell setenforce 0\" to enable "
+              "surfaceflinger to write debug images");
+        return;
+    }
+
+    file << "P6\n";
+    file << width << "\n";
+    file << height << "\n";
+    file << 255 << "\n";
+
+    auto ptr = reinterpret_cast<char*>(pixels.data());
+    auto outPtr = reinterpret_cast<char*>(outBuffer.data());
+    for (int y = height - 1; y >= 0; y--) {
+        char* data = ptr + y * width * sizeof(uint32_t);
+
+        for (GLuint x = 0; x < width; x++) {
+            // Only copy R, G and B components
+            outPtr[0] = data[0];
+            outPtr[1] = data[1];
+            outPtr[2] = data[2];
+            data += sizeof(uint32_t);
+            outPtr += 3;
+        }
+    }
+    file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
+}
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+using base::StringAppendF;
+using ui::Dataspace;
+
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+                                         EGLint wanted, EGLConfig* outConfig) {
+    EGLint numConfigs = -1, n = 0;
+    eglGetConfigs(dpy, nullptr, 0, &numConfigs);
+    std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
+    eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n);
+    configs.resize(n);
+
+    if (!configs.empty()) {
+        if (attribute != EGL_NONE) {
+            for (EGLConfig config : configs) {
+                EGLint value = 0;
+                eglGetConfigAttrib(dpy, config, attribute, &value);
+                if (wanted == value) {
+                    *outConfig = config;
+                    return NO_ERROR;
+                }
+            }
+        } else {
+            // just pick the first one
+            *outConfig = configs[0];
+            return NO_ERROR;
+        }
+    }
+
+    return NAME_NOT_FOUND;
+}
+
+class EGLAttributeVector {
+    struct Attribute;
+    class Adder;
+    friend class Adder;
+    KeyedVector<Attribute, EGLint> mList;
+    struct Attribute {
+        Attribute() : v(0){};
+        explicit Attribute(EGLint v) : v(v) {}
+        EGLint v;
+        bool operator<(const Attribute& other) const {
+            // this places EGL_NONE at the end
+            EGLint lhs(v);
+            EGLint rhs(other.v);
+            if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
+            if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
+            return lhs < rhs;
+        }
+    };
+    class Adder {
+        friend class EGLAttributeVector;
+        EGLAttributeVector& v;
+        EGLint attribute;
+        Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
+
+    public:
+        void operator=(EGLint value) {
+            if (attribute != EGL_NONE) {
+                v.mList.add(Attribute(attribute), value);
+            }
+        }
+        operator EGLint() const { return v.mList[attribute]; }
+    };
+
+public:
+    EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
+    void remove(EGLint attribute) {
+        if (attribute != EGL_NONE) {
+            mList.removeItem(Attribute(attribute));
+        }
+    }
+    Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
+    EGLint operator[](EGLint attribute) const { return mList[attribute]; }
+    // cast-operator to (EGLint const*)
+    operator EGLint const*() const { return &mList.keyAt(0).v; }
+};
+
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+                                EGLConfig* config) {
+    // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
+    // it is to be used with WIFI displays
+    status_t err;
+    EGLint wantedAttribute;
+    EGLint wantedAttributeValue;
+
+    EGLAttributeVector attribs;
+    if (renderableType) {
+        attribs[EGL_RENDERABLE_TYPE] = renderableType;
+        attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
+        attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
+        attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
+        attribs[EGL_RED_SIZE] = 8;
+        attribs[EGL_GREEN_SIZE] = 8;
+        attribs[EGL_BLUE_SIZE] = 8;
+        attribs[EGL_ALPHA_SIZE] = 8;
+        wantedAttribute = EGL_NONE;
+        wantedAttributeValue = EGL_NONE;
+    } else {
+        // if no renderable type specified, fallback to a simplified query
+        wantedAttribute = EGL_NATIVE_VISUAL_ID;
+        wantedAttributeValue = format;
+    }
+
+    err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
+    if (err == NO_ERROR) {
+        EGLint caveat;
+        if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
+            ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
+    }
+
+    return err;
+}
+
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
+                                                           uint32_t imageCacheSize) {
+    // initialize EGL for the default display
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (!eglInitialize(display, nullptr, nullptr)) {
+        LOG_ALWAYS_FATAL("failed to initialize EGL");
+    }
+
+    GLExtensions& extensions = GLExtensions::getInstance();
+    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
+                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+
+    // The code assumes that ES2 or later is available if this extension is
+    // supported.
+    EGLConfig config = EGL_NO_CONFIG;
+    if (!extensions.hasNoConfigContext()) {
+        config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+    }
+
+    bool useContextPriority = extensions.hasContextPriority() &&
+            (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+    EGLContext protectedContext = EGL_NO_CONTEXT;
+    if ((featureFlags & RenderEngine::ENABLE_PROTECTED_CONTEXT) &&
+        extensions.hasProtectedContent()) {
+        protectedContext = createEglContext(display, config, nullptr, useContextPriority,
+                                            Protection::PROTECTED);
+        ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
+    }
+
+    EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority,
+                                       Protection::UNPROTECTED);
+
+    // if can't create a GL context, we can only abort.
+    LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
+
+    EGLSurface dummy = EGL_NO_SURFACE;
+    if (!extensions.hasSurfacelessContext()) {
+        dummy = createDummyEglPbufferSurface(display, config, hwcFormat, Protection::UNPROTECTED);
+        LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
+    }
+    EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
+    LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
+    extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+                                 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
+
+    EGLSurface protectedDummy = EGL_NO_SURFACE;
+    if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
+        protectedDummy =
+                createDummyEglPbufferSurface(display, config, hwcFormat, Protection::PROTECTED);
+        ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer");
+    }
+
+    // now figure out what version of GL did we actually get
+    GlesVersion version = parseGlesVersion(extensions.getVersion());
+
+    // initialize the renderer while GL is current
+    std::unique_ptr<GLESRenderEngine> engine;
+    switch (version) {
+        case GLES_VERSION_1_0:
+        case GLES_VERSION_1_1:
+            LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
+            break;
+        case GLES_VERSION_2_0:
+        case GLES_VERSION_3_0:
+            engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
+                                                        protectedContext, protectedDummy,
+                                                        imageCacheSize);
+            break;
+    }
+
+    ALOGI("OpenGL ES informations:");
+    ALOGI("vendor    : %s", extensions.getVendor());
+    ALOGI("renderer  : %s", extensions.getRenderer());
+    ALOGI("version   : %s", extensions.getVersion());
+    ALOGI("extensions: %s", extensions.getExtensions());
+    ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
+    ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
+
+    return engine;
+}
+
+EGLConfig GLESRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
+    status_t err;
+    EGLConfig config;
+
+    // First try to get an ES3 config
+    err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config);
+    if (err != NO_ERROR) {
+        // If ES3 fails, try to get an ES2 config
+        err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
+        if (err != NO_ERROR) {
+            // If ES2 still doesn't work, probably because we're on the emulator.
+            // try a simplified query
+            ALOGW("no suitable EGLConfig found, trying a simpler query");
+            err = selectEGLConfig(display, format, 0, &config);
+            if (err != NO_ERROR) {
+                // this EGL is too lame for android
+                LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
+            }
+        }
+    }
+
+    if (logConfig) {
+        // print some debugging info
+        EGLint r, g, b, a;
+        eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+        eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+        eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+        ALOGI("EGL information:");
+        ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
+        ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
+        ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
+        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
+        ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+    }
+
+    return config;
+}
+
+GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
+                                   EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
+                                   EGLSurface protectedDummy, uint32_t imageCacheSize)
+      : renderengine::impl::RenderEngine(featureFlags),
+        mEGLDisplay(display),
+        mEGLConfig(config),
+        mEGLContext(ctxt),
+        mDummySurface(dummy),
+        mProtectedEGLContext(protectedContext),
+        mProtectedDummySurface(protectedDummy),
+        mVpWidth(0),
+        mVpHeight(0),
+        mFramebufferImageCacheSize(imageCacheSize),
+        mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+    // Initialize protected EGL Context.
+    if (mProtectedEGLContext != EGL_NO_CONTEXT) {
+        EGLBoolean success = eglMakeCurrent(display, mProtectedDummySurface, mProtectedDummySurface,
+                                            mProtectedEGLContext);
+        ALOGE_IF(!success, "can't make protected context current");
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+        glPixelStorei(GL_PACK_ALIGNMENT, 4);
+        success = eglMakeCurrent(display, mDummySurface, mDummySurface, mEGLContext);
+        LOG_ALWAYS_FATAL_IF(!success, "can't make default context current");
+    }
+
+    const uint16_t protTexData[] = {0};
+    glGenTextures(1, &mProtectedTexName);
+    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
+
+    // mColorBlindnessCorrection = M;
+
+    if (mUseColorManagement) {
+        const ColorSpace srgb(ColorSpace::sRGB());
+        const ColorSpace displayP3(ColorSpace::DisplayP3());
+        const ColorSpace bt2020(ColorSpace::BT2020());
+
+        // no chromatic adaptation needed since all color spaces use D65 for their white points.
+        mSrgbToXyz = mat4(srgb.getRGBtoXYZ());
+        mDisplayP3ToXyz = mat4(displayP3.getRGBtoXYZ());
+        mBt2020ToXyz = mat4(bt2020.getRGBtoXYZ());
+        mXyzToSrgb = mat4(srgb.getXYZtoRGB());
+        mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
+        mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
+
+        // Compute sRGB to Display P3 and BT2020 transform matrix.
+        // NOTE: For now, we are limiting output wide color space support to
+        // Display-P3 and BT2020 only.
+        mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz;
+        mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz;
+
+        // Compute Display P3 to sRGB and BT2020 transform matrix.
+        mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz;
+        mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz;
+
+        // Compute BT2020 to sRGB and Display P3 transform matrix
+        mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz;
+        mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz;
+    }
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.egl.traceGpuCompletion", value, "0");
+    if (atoi(value)) {
+        mTraceGpuCompletion = true;
+        mFlushTracer = std::make_unique<FlushTracer>(this);
+    }
+    mDrawingBuffer = createFramebuffer();
+}
+
+GLESRenderEngine::~GLESRenderEngine() {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    unbindFrameBuffer(mDrawingBuffer.get());
+    mDrawingBuffer = nullptr;
+    while (!mFramebufferImageCache.empty()) {
+        EGLImageKHR expired = mFramebufferImageCache.front().second;
+        mFramebufferImageCache.pop_front();
+        eglDestroyImageKHR(mEGLDisplay, expired);
+    }
+    mImageCache.clear();
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mEGLDisplay);
+}
+
+std::unique_ptr<Framebuffer> GLESRenderEngine::createFramebuffer() {
+    return std::make_unique<GLFramebuffer>(*this);
+}
+
+std::unique_ptr<Image> GLESRenderEngine::createImage() {
+    return std::make_unique<GLImage>(*this);
+}
+
+Framebuffer* GLESRenderEngine::getFramebufferForDrawing() {
+    return mDrawingBuffer.get();
+}
+
+void GLESRenderEngine::primeCache() const {
+    ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
+                                           mFeatureFlags & USE_COLOR_MANAGEMENT);
+}
+
+bool GLESRenderEngine::isCurrent() const {
+    return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
+}
+
+base::unique_fd GLESRenderEngine::flush() {
+    ATRACE_CALL();
+    if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+        return base::unique_fd();
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+        return base::unique_fd();
+    }
+
+    // native fence fd will not be populated until flush() is done.
+    glFlush();
+
+    // get the fence fd
+    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+    }
+
+    // Only trace if we have a valid fence, as current usage falls back to
+    // calling finish() if the fence fd is invalid.
+    if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) {
+        mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr));
+    }
+
+    return fenceFd;
+}
+
+bool GLESRenderEngine::finish() {
+    ATRACE_CALL();
+    if (!GLExtensions::getInstance().hasFenceSync()) {
+        ALOGW("no synchronization support");
+        return false;
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) {
+        mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr));
+    }
+
+    return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR);
+}
+
+bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) {
+    EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (result != EGL_CONDITION_SATISFIED_KHR) {
+        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ALOGW("fence wait timed out");
+        } else {
+            ALOGW("error waiting on EGL fence: %#x", error);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool GLESRenderEngine::waitFence(base::unique_fd fenceFd) {
+    if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+        !GLExtensions::getInstance().hasWaitSync()) {
+        return false;
+    }
+
+    // release the fd and transfer the ownership to EGLSync
+    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE};
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    // XXX: The spec draft is inconsistent as to whether this should return an
+    // EGLint or void.  Ignore the return value for now, as it's not strictly
+    // needed.
+    eglWaitSyncKHR(mEGLDisplay, sync, 0);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (error != EGL_SUCCESS) {
+        ALOGE("failed to wait for EGL native fence sync: %#x", error);
+        return false;
+    }
+
+    return true;
+}
+
+void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+    ATRACE_CALL();
+    glDisable(GL_BLEND);
+    glClearColor(red, green, blue, alpha);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void GLESRenderEngine::fillRegionWithColor(const Region& region, float red, float green, float blue,
+                                           float alpha) {
+    size_t c;
+    Rect const* r = region.getArray(&c);
+    Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
+    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+    for (size_t i = 0; i < c; i++, r++) {
+        position[i * 6 + 0].x = r->left;
+        position[i * 6 + 0].y = r->top;
+        position[i * 6 + 1].x = r->left;
+        position[i * 6 + 1].y = r->bottom;
+        position[i * 6 + 2].x = r->right;
+        position[i * 6 + 2].y = r->bottom;
+        position[i * 6 + 3].x = r->left;
+        position[i * 6 + 3].y = r->top;
+        position[i * 6 + 4].x = r->right;
+        position[i * 6 + 4].y = r->bottom;
+        position[i * 6 + 5].x = r->right;
+        position[i * 6 + 5].y = r->top;
+    }
+    setupFillWithColor(red, green, blue, alpha);
+    drawMesh(mesh);
+}
+
+void GLESRenderEngine::setScissor(const Rect& region) {
+    glScissor(region.left, region.top, region.getWidth(), region.getHeight());
+    glEnable(GL_SCISSOR_TEST);
+}
+
+void GLESRenderEngine::disableScissor() {
+    glDisable(GL_SCISSOR_TEST);
+}
+
+void GLESRenderEngine::genTextures(size_t count, uint32_t* names) {
+    glGenTextures(count, names);
+}
+
+void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+    glDeleteTextures(count, names);
+}
+
+void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
+    ATRACE_CALL();
+    const GLImage& glImage = static_cast<const GLImage&>(image);
+    const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+    glBindTexture(target, texName);
+    if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
+        glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
+    }
+}
+
+status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    return cacheExternalTextureBufferLocked(buffer);
+}
+
+status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
+                                                     const sp<GraphicBuffer>& buffer,
+                                                     const sp<Fence>& bufferFence) {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    return bindExternalTextureBufferLocked(texName, buffer, bufferFence);
+}
+
+status_t GLESRenderEngine::cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) {
+    if (buffer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    ATRACE_CALL();
+
+    if (mImageCache.count(buffer->getId()) > 0) {
+        return NO_ERROR;
+    }
+
+    std::unique_ptr<Image> newImage = createImage();
+
+    bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
+                                                   buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    if (!created) {
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
+              buffer->getPixelFormat());
+        return NO_INIT;
+    }
+    mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
+
+    return NO_ERROR;
+}
+
+status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
+                                                           const sp<GraphicBuffer>& buffer,
+                                                           const sp<Fence>& bufferFence) {
+    ATRACE_CALL();
+    status_t cacheResult = cacheExternalTextureBufferLocked(buffer);
+
+    if (cacheResult != NO_ERROR) {
+        return cacheResult;
+    }
+
+    auto cachedImage = mImageCache.find(buffer->getId());
+
+    if (cachedImage == mImageCache.end()) {
+        // We failed creating the image if we got here, so bail out.
+        bindExternalTextureImage(texName, *createImage());
+        return NO_INIT;
+    }
+
+    bindExternalTextureImage(texName, *cachedImage->second);
+
+    // Wait for the new buffer to be ready.
+    if (bufferFence != nullptr && bufferFence->isValid()) {
+        if (GLExtensions::getInstance().hasWaitSync()) {
+            base::unique_fd fenceFd(bufferFence->dup());
+            if (fenceFd == -1) {
+                ALOGE("error dup'ing fence fd: %d", errno);
+                return -errno;
+            }
+            if (!waitFence(std::move(fenceFd))) {
+                ALOGE("failed to wait on fence fd");
+                return UNKNOWN_ERROR;
+            }
+        } else {
+            status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer");
+            if (err != NO_ERROR) {
+                ALOGE("error waiting for fence: %d", err);
+                return err;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    const auto& cachedImage = mImageCache.find(bufferId);
+    if (cachedImage != mImageCache.end()) {
+        ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+        mImageCache.erase(bufferId);
+        return;
+    }
+    ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
+}
+
+FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
+    // Translate win by the rounded corners rect coordinates, to have all values in
+    // layer coordinate space.
+    FloatRect cropWin = layer.geometry.boundaries;
+    const FloatRect& roundedCornersCrop = layer.geometry.roundedCornersCrop;
+    cropWin.left -= roundedCornersCrop.left;
+    cropWin.right -= roundedCornersCrop.left;
+    cropWin.top -= roundedCornersCrop.top;
+    cropWin.bottom -= roundedCornersCrop.top;
+    Mesh::VertexArray<vec2> cropCoords(mesh.getCropCoordArray<vec2>());
+    cropCoords[0] = vec2(cropWin.left, cropWin.top);
+    cropCoords[1] = vec2(cropWin.left, cropWin.top + cropWin.getHeight());
+    cropCoords[2] = vec2(cropWin.right, cropWin.top + cropWin.getHeight());
+    cropCoords[3] = vec2(cropWin.right, cropWin.top);
+
+    setupCornerRadiusCropSize(roundedCornersCrop.getWidth(), roundedCornersCrop.getHeight());
+    return cropWin;
+}
+
+void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display,
+                                            const LayerSettings& layer, const Mesh& mesh) {
+    // We separate the layer into 3 parts essentially, such that we only turn on blending for the
+    // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
+    FloatRect bounds = layer.geometry.roundedCornersCrop;
+
+    // Firstly, we need to convert the coordination from layer native coordination space to
+    // device coordination space.
+    const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
+    const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
+    const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
+    const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
+    const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
+    bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
+                       rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
+
+    // Secondly, if the display is rotated, we need to undo the rotation on coordination and
+    // align the (left, top) and (right, bottom) coordination with the device coordination
+    // space.
+    switch (display.orientation) {
+        case ui::Transform::ROT_90:
+            std::swap(bounds.left, bounds.right);
+            break;
+        case ui::Transform::ROT_180:
+            std::swap(bounds.left, bounds.right);
+            std::swap(bounds.top, bounds.bottom);
+            break;
+        case ui::Transform::ROT_270:
+            std::swap(bounds.top, bounds.bottom);
+            break;
+        default:
+            break;
+    }
+
+    // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
+    // and the middle part without rounded corners.
+    const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
+    const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
+    setScissor(topRect);
+    drawMesh(mesh);
+    const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom);
+    setScissor(bottomRect);
+    drawMesh(mesh);
+
+    // The middle part of the layer can turn off blending.
+    const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, bounds.bottom - radius);
+    setScissor(middleRect);
+    mState.cornerRadius = 0.0;
+    disableBlending();
+    drawMesh(mesh);
+    disableScissor();
+}
+
+status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
+    ATRACE_CALL();
+    GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
+    EGLImageKHR eglImage = glFramebuffer->getEGLImage();
+    uint32_t textureName = glFramebuffer->getTextureName();
+    uint32_t framebufferName = glFramebuffer->getFramebufferName();
+
+    // Bind the texture and turn our EGLImage into a texture
+    glBindTexture(GL_TEXTURE_2D, textureName);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
+
+    // Bind the Framebuffer to render into
+    glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
+
+    uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+    ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
+             glStatus);
+
+    return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
+}
+
+void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+    ATRACE_CALL();
+
+    // back to main framebuffer
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void GLESRenderEngine::checkErrors() const {
+    do {
+        // there could be more than one error flag
+        GLenum error = glGetError();
+        if (error == GL_NO_ERROR) break;
+        ALOGE("GL error 0x%04x", int(error));
+    } while (true);
+}
+
+bool GLESRenderEngine::supportsProtectedContent() const {
+    return mProtectedEGLContext != EGL_NO_CONTEXT;
+}
+
+bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
+    if (useProtectedContext == mInProtectedContext) {
+        return true;
+    }
+    if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
+        return false;
+    }
+    const EGLSurface surface = useProtectedContext ? mProtectedDummySurface : mDummySurface;
+    const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
+    const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
+    if (success) {
+        mInProtectedContext = useProtectedContext;
+    }
+    return success;
+}
+EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
+                                                             bool isProtected,
+                                                             bool useFramebufferCache) {
+    sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
+    if (useFramebufferCache) {
+        for (const auto& image : mFramebufferImageCache) {
+            if (image.first == graphicBuffer->getId()) {
+                return image.second;
+            }
+        }
+    }
+    EGLint attributes[] = {
+            isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+            isProtected ? EGL_TRUE : EGL_NONE,
+            EGL_NONE,
+    };
+    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                          nativeBuffer, attributes);
+    if (useFramebufferCache) {
+        if (image != EGL_NO_IMAGE_KHR) {
+            if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
+                EGLImageKHR expired = mFramebufferImageCache.front().second;
+                mFramebufferImageCache.pop_front();
+                eglDestroyImageKHR(mEGLDisplay, expired);
+            }
+            mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
+        }
+    }
+    return image;
+}
+
+status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
+                                      const std::vector<LayerSettings>& layers,
+                                      ANativeWindowBuffer* const buffer,
+                                      const bool useFramebufferCache, base::unique_fd&& bufferFence,
+                                      base::unique_fd* drawFence) {
+    ATRACE_CALL();
+    if (layers.empty()) {
+        ALOGV("Drawing empty layer stack");
+        return NO_ERROR;
+    }
+
+    if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
+        ATRACE_NAME("Waiting before draw");
+        sync_wait(bufferFence.get(), -1);
+    }
+
+    if (buffer == nullptr) {
+        ALOGE("No output buffer provided. Aborting GPU composition.");
+        return BAD_VALUE;
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+        BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
+
+        if (fbo.getStatus() != NO_ERROR) {
+            ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+                  buffer->handle);
+            checkErrors();
+            return fbo.getStatus();
+        }
+
+        // clear the entire buffer, sometimes when we reuse buffers we'd persist
+        // ghost images otherwise.
+        // we also require a full transparent framebuffer for overlays. This is
+        // probably not quite efficient on all GPUs, since we could filter out
+        // opaque layers.
+        clearWithColor(0.0, 0.0, 0.0, 0.0);
+
+        setViewportAndProjection(display.physicalDisplay, display.clip);
+
+        setOutputDataSpace(display.outputDataspace);
+        setDisplayMaxLuminance(display.maxLuminance);
+
+        mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
+        mState.projectionMatrix = projectionMatrix;
+        if (!display.clearRegion.isEmpty()) {
+            glDisable(GL_BLEND);
+            fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
+        }
+
+        Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
+        for (auto layer : layers) {
+            mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+
+            const FloatRect bounds = layer.geometry.boundaries;
+            Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+            position[0] = vec2(bounds.left, bounds.top);
+            position[1] = vec2(bounds.left, bounds.bottom);
+            position[2] = vec2(bounds.right, bounds.bottom);
+            position[3] = vec2(bounds.right, bounds.top);
+
+            setupLayerCropping(layer, mesh);
+            setColorTransform(display.colorTransform * layer.colorTransform);
+
+            bool usePremultipliedAlpha = true;
+            bool disableTexture = true;
+            bool isOpaque = false;
+
+            if (layer.source.buffer.buffer != nullptr) {
+                disableTexture = false;
+                isOpaque = layer.source.buffer.isOpaque;
+
+                sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
+                bindExternalTextureBufferLocked(layer.source.buffer.textureName, gBuf,
+                                                layer.source.buffer.fence);
+
+                usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
+                Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
+                mat4 texMatrix = layer.source.buffer.textureTransform;
+
+                texture.setMatrix(texMatrix.asArray());
+                texture.setFiltering(layer.source.buffer.useTextureFiltering);
+
+                texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
+                setSourceY410BT2020(layer.source.buffer.isY410BT2020);
+
+                renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
+                texCoords[0] = vec2(0.0, 0.0);
+                texCoords[1] = vec2(0.0, 1.0);
+                texCoords[2] = vec2(1.0, 1.0);
+                texCoords[3] = vec2(1.0, 0.0);
+                setupLayerTexturing(texture);
+            }
+
+            const half3 solidColor = layer.source.solidColor;
+            const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+            // Buffer sources will have a black solid color ignored in the shader,
+            // so in that scenario the solid color passed here is arbitrary.
+            setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
+                               layer.geometry.roundedCornersRadius);
+            if (layer.disableBlending) {
+                glDisable(GL_BLEND);
+            }
+            setSourceDataSpace(layer.sourceDataspace);
+
+            // We only want to do a special handling for rounded corners when having rounded corners
+            // is the only reason it needs to turn on blending, otherwise, we handle it like the
+            // usual way since it needs to turn on blending anyway.
+            if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+                handleRoundedCorners(display, layer, mesh);
+            } else {
+                drawMesh(mesh);
+            }
+
+            // Cleanup if there's a buffer source
+            if (layer.source.buffer.buffer != nullptr) {
+                disableBlending();
+                setSourceY410BT2020(false);
+                disableTexturing();
+            }
+        }
+
+        if (drawFence != nullptr) {
+            *drawFence = flush();
+        }
+        // If flush failed or we don't support native fences, we need to force the
+        // gl command stream to be executed.
+        if (drawFence == nullptr || drawFence->get() < 0) {
+            bool success = finish();
+            if (!success) {
+                ALOGE("Failed to flush RenderEngine commands");
+                checkErrors();
+                // Chances are, something illegal happened (either the caller passed
+                // us bad parameters, or we messed up our shader generation).
+                return INVALID_OPERATION;
+            }
+        }
+
+        checkErrors();
+    }
+    return NO_ERROR;
+}
+
+void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+                                                ui::Transform::orientation_flags rotation) {
+    setViewportAndProjection(Rect(vpw, vph), sourceCrop);
+
+    if (rotation == ui::Transform::ROT_0) {
+        return;
+    }
+
+    // Apply custom rotation to the projection.
+    float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+    mat4 m = mState.projectionMatrix;
+    switch (rotation) {
+        case ui::Transform::ROT_90:
+            m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
+            break;
+        case ui::Transform::ROT_180:
+            m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
+            break;
+        case ui::Transform::ROT_270:
+            m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
+            break;
+        default:
+            break;
+    }
+    mState.projectionMatrix = m;
+}
+
+void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
+    ATRACE_CALL();
+    mVpWidth = viewport.getWidth();
+    mVpHeight = viewport.getHeight();
+
+    // We pass the the top left corner instead of the bottom left corner,
+    // because since we're rendering off-screen first.
+    glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight);
+
+    mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1);
+}
+
+void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                          const half4& color, float cornerRadius) {
+    mState.isPremultipliedAlpha = premultipliedAlpha;
+    mState.isOpaque = opaque;
+    mState.color = color;
+    mState.cornerRadius = cornerRadius;
+
+    if (disableTexture) {
+        mState.textureEnabled = false;
+    }
+
+    if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) {
+        glEnable(GL_BLEND);
+        glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    } else {
+        glDisable(GL_BLEND);
+    }
+}
+
+void GLESRenderEngine::setSourceY410BT2020(bool enable) {
+    mState.isY410BT2020 = enable;
+}
+
+void GLESRenderEngine::setSourceDataSpace(Dataspace source) {
+    mDataSpace = source;
+}
+
+void GLESRenderEngine::setOutputDataSpace(Dataspace dataspace) {
+    mOutputDataSpace = dataspace;
+}
+
+void GLESRenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
+    mState.displayMaxLuminance = maxLuminance;
+}
+
+void GLESRenderEngine::setupLayerTexturing(const Texture& texture) {
+    GLuint target = texture.getTextureTarget();
+    glBindTexture(target, texture.getTextureName());
+    GLenum filter = GL_NEAREST;
+    if (texture.getFiltering()) {
+        filter = GL_LINEAR;
+    }
+    glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
+    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
+
+    mState.texture = texture;
+    mState.textureEnabled = true;
+}
+
+void GLESRenderEngine::setupLayerBlackedOut() {
+    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+    Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
+    texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
+    mState.texture = texture;
+    mState.textureEnabled = true;
+}
+
+void GLESRenderEngine::setColorTransform(const mat4& colorTransform) {
+    mState.colorMatrix = colorTransform;
+}
+
+void GLESRenderEngine::disableTexturing() {
+    mState.textureEnabled = false;
+}
+
+void GLESRenderEngine::disableBlending() {
+    glDisable(GL_BLEND);
+}
+
+void GLESRenderEngine::setupFillWithColor(float r, float g, float b, float a) {
+    mState.isPremultipliedAlpha = true;
+    mState.isOpaque = false;
+    mState.color = half4(r, g, b, a);
+    mState.textureEnabled = false;
+    glDisable(GL_BLEND);
+}
+
+void GLESRenderEngine::setupCornerRadiusCropSize(float width, float height) {
+    mState.cropSize = half2(width, height);
+}
+
+void GLESRenderEngine::drawMesh(const Mesh& mesh) {
+    ATRACE_CALL();
+    if (mesh.getTexCoordsSize()) {
+        glEnableVertexAttribArray(Program::texCoords);
+        glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
+                              mesh.getByteStride(), mesh.getTexCoords());
+    }
+
+    glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+                          mesh.getByteStride(), mesh.getPositions());
+
+    if (mState.cornerRadius > 0.0f) {
+        glEnableVertexAttribArray(Program::cropCoords);
+        glVertexAttribPointer(Program::cropCoords, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+                              mesh.getByteStride(), mesh.getCropCoords());
+    }
+
+    // By default, DISPLAY_P3 is the only supported wide color output. However,
+    // when HDR content is present, hardware composer may be able to handle
+    // BT2020 data space, in that case, the output data space is set to be
+    // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
+    // to respect this and convert non-HDR content to HDR format.
+    if (mUseColorManagement) {
+        Description managedState = mState;
+        Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
+        Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+        Dataspace outputStandard =
+                static_cast<Dataspace>(mOutputDataSpace & Dataspace::STANDARD_MASK);
+        Dataspace outputTransfer =
+                static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
+        bool needsXYZConversion = needsXYZTransformMatrix();
+
+        // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or
+        // STANDARD_BT2020, it will be  treated as STANDARD_BT709
+        if (inputStandard != Dataspace::STANDARD_DCI_P3 &&
+            inputStandard != Dataspace::STANDARD_BT2020) {
+            inputStandard = Dataspace::STANDARD_BT709;
+        }
+
+        if (needsXYZConversion) {
+            // The supported input color spaces are standard RGB, Display P3 and BT2020.
+            switch (inputStandard) {
+                case Dataspace::STANDARD_DCI_P3:
+                    managedState.inputTransformMatrix = mDisplayP3ToXyz;
+                    break;
+                case Dataspace::STANDARD_BT2020:
+                    managedState.inputTransformMatrix = mBt2020ToXyz;
+                    break;
+                default:
+                    managedState.inputTransformMatrix = mSrgbToXyz;
+                    break;
+            }
+
+            // The supported output color spaces are BT2020, Display P3 and standard RGB.
+            switch (outputStandard) {
+                case Dataspace::STANDARD_BT2020:
+                    managedState.outputTransformMatrix = mXyzToBt2020;
+                    break;
+                case Dataspace::STANDARD_DCI_P3:
+                    managedState.outputTransformMatrix = mXyzToDisplayP3;
+                    break;
+                default:
+                    managedState.outputTransformMatrix = mXyzToSrgb;
+                    break;
+            }
+        } else if (inputStandard != outputStandard) {
+            // At this point, the input data space and output data space could be both
+            // HDR data spaces, but they match each other, we do nothing in this case.
+            // In addition to the case above, the input data space could be
+            // - scRGB linear
+            // - scRGB non-linear
+            // - sRGB
+            // - Display P3
+            // - BT2020
+            // The output data spaces could be
+            // - sRGB
+            // - Display P3
+            // - BT2020
+            switch (outputStandard) {
+                case Dataspace::STANDARD_BT2020:
+                    if (inputStandard == Dataspace::STANDARD_BT709) {
+                        managedState.outputTransformMatrix = mSrgbToBt2020;
+                    } else if (inputStandard == Dataspace::STANDARD_DCI_P3) {
+                        managedState.outputTransformMatrix = mDisplayP3ToBt2020;
+                    }
+                    break;
+                case Dataspace::STANDARD_DCI_P3:
+                    if (inputStandard == Dataspace::STANDARD_BT709) {
+                        managedState.outputTransformMatrix = mSrgbToDisplayP3;
+                    } else if (inputStandard == Dataspace::STANDARD_BT2020) {
+                        managedState.outputTransformMatrix = mBt2020ToDisplayP3;
+                    }
+                    break;
+                default:
+                    if (inputStandard == Dataspace::STANDARD_DCI_P3) {
+                        managedState.outputTransformMatrix = mDisplayP3ToSrgb;
+                    } else if (inputStandard == Dataspace::STANDARD_BT2020) {
+                        managedState.outputTransformMatrix = mBt2020ToSrgb;
+                    }
+                    break;
+            }
+        }
+
+        // we need to convert the RGB value to linear space and convert it back when:
+        // - there is a color matrix that is not an identity matrix, or
+        // - there is an output transform matrix that is not an identity matrix, or
+        // - the input transfer function doesn't match the output transfer function.
+        if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() ||
+            inputTransfer != outputTransfer) {
+            managedState.inputTransferFunction =
+                    Description::dataSpaceToTransferFunction(inputTransfer);
+            managedState.outputTransferFunction =
+                    Description::dataSpaceToTransferFunction(outputTransfer);
+        }
+
+        ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext
+                                                                   : mEGLContext,
+                                               managedState);
+
+        glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+
+        if (outputDebugPPMs) {
+            static uint64_t managedColorFrameCount = 0;
+            std::ostringstream out;
+            out << "/data/texture_out" << managedColorFrameCount++;
+            writePPM(out.str().c_str(), mVpWidth, mVpHeight);
+        }
+    } else {
+        ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext
+                                                                   : mEGLContext,
+                                               mState);
+
+        glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
+    }
+
+    if (mesh.getTexCoordsSize()) {
+        glDisableVertexAttribArray(Program::texCoords);
+    }
+
+    if (mState.cornerRadius > 0.0f) {
+        glDisableVertexAttribArray(Program::cropCoords);
+    }
+}
+
+size_t GLESRenderEngine::getMaxTextureSize() const {
+    return mMaxTextureSize;
+}
+
+size_t GLESRenderEngine::getMaxViewportDims() const {
+    return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
+}
+
+void GLESRenderEngine::dump(std::string& result) {
+    const GLExtensions& extensions = GLExtensions::getInstance();
+    ProgramCache& cache = ProgramCache::getInstance();
+
+    StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
+    StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
+    StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+                  extensions.getVersion());
+    StringAppendF(&result, "%s\n", extensions.getExtensions());
+    StringAppendF(&result, "RenderEngine supports protected context: %d\n",
+                  supportsProtectedContent());
+    StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
+    StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n",
+                  cache.getSize(mEGLContext));
+    StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n",
+                  cache.getSize(mProtectedEGLContext));
+    StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n",
+                  dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+                  dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
+}
+
+GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) {
+    int major, minor;
+    if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
+        if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
+            ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
+            return GLES_VERSION_1_0;
+        }
+    }
+
+    if (major == 1 && minor == 0) return GLES_VERSION_1_0;
+    if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
+    if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
+    if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
+
+    ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
+    return GLES_VERSION_1_0;
+}
+
+EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
+                                              EGLContext shareContext, bool useContextPriority,
+                                              Protection protection) {
+    EGLint renderableType = 0;
+    if (config == EGL_NO_CONFIG) {
+        renderableType = EGL_OPENGL_ES3_BIT;
+    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
+        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
+    }
+    EGLint contextClientVersion = 0;
+    if (renderableType & EGL_OPENGL_ES3_BIT) {
+        contextClientVersion = 3;
+    } else if (renderableType & EGL_OPENGL_ES2_BIT) {
+        contextClientVersion = 2;
+    } else if (renderableType & EGL_OPENGL_ES_BIT) {
+        contextClientVersion = 1;
+    } else {
+        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
+    }
+
+    std::vector<EGLint> contextAttributes;
+    contextAttributes.reserve(7);
+    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+    contextAttributes.push_back(contextClientVersion);
+    if (useContextPriority) {
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+    }
+    if (protection == Protection::PROTECTED) {
+        contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
+        contextAttributes.push_back(EGL_TRUE);
+    }
+    contextAttributes.push_back(EGL_NONE);
+
+    EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data());
+
+    if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) {
+        // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus
+        // EGL_NO_CONTEXT so that we can abort.
+        if (config != EGL_NO_CONFIG) {
+            return context;
+        }
+        // If |config| is EGL_NO_CONFIG, we speculatively try to create GLES 3 context, so we should
+        // try to fall back to GLES 2.
+        contextAttributes[1] = 2;
+        context = eglCreateContext(display, config, shareContext, contextAttributes.data());
+    }
+
+    return context;
+}
+
+EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                          int hwcFormat, Protection protection) {
+    EGLConfig dummyConfig = config;
+    if (dummyConfig == EGL_NO_CONFIG) {
+        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+    }
+    std::vector<EGLint> attributes;
+    attributes.reserve(7);
+    attributes.push_back(EGL_WIDTH);
+    attributes.push_back(1);
+    attributes.push_back(EGL_HEIGHT);
+    attributes.push_back(1);
+    if (protection == Protection::PROTECTED) {
+        attributes.push_back(EGL_PROTECTED_CONTENT_EXT);
+        attributes.push_back(EGL_TRUE);
+    }
+    attributes.push_back(EGL_NONE);
+
+    return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
+}
+
+bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
+    const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
+    const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
+    return standard == Dataspace::STANDARD_BT2020 &&
+            (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
+}
+
+// For convenience, we want to convert the input color space to XYZ color space first,
+// and then convert from XYZ color space to output color space when
+// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or
+//   HDR content will be tone-mapped to SDR; Or,
+// - there are HDR PQ and HLG contents presented at the same time, where we want to convert
+//   HLG content to PQ content.
+// In either case above, we need to operate the Y value in XYZ color space. Thus, when either
+// input data space or output data space is HDR data space, and the input transfer function
+// doesn't match the output transfer function, we would enable an intermediate transfrom to
+// XYZ color space.
+bool GLESRenderEngine::needsXYZTransformMatrix() const {
+    const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
+    const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
+    const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
+    const Dataspace outputTransfer =
+            static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
+
+    return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
+}
+
+bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    const auto& cachedImage = mImageCache.find(bufferId);
+    return cachedImage != mImageCache.end();
+}
+
+bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(),
+                       [=](std::pair<uint64_t, EGLImageKHR> image) {
+                           return image.first == bufferId;
+                       });
+}
+
+// FlushTracer implementation
+GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) {
+    mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this);
+}
+
+GLESRenderEngine::FlushTracer::~FlushTracer() {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mRunning = false;
+    }
+    mCondition.notify_all();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    char name[64];
+    const uint64_t frameNum = mFramesQueued++;
+    snprintf(name, sizeof(name), "Queueing sync for frame: %lu",
+             static_cast<unsigned long>(frameNum));
+    ATRACE_NAME(name);
+    mQueue.push({sync, frameNum});
+    ATRACE_INT("GPU Frames Outstanding", mQueue.size());
+    mCondition.notify_one();
+}
+
+void GLESRenderEngine::FlushTracer::loop() {
+    while (mRunning) {
+        QueueEntry entry;
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+
+            mCondition.wait(mMutex,
+                            [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
+
+            if (!mRunning) {
+                // if mRunning is false, then FlushTracer is being destroyed, so
+                // bail out now.
+                break;
+            }
+            entry = mQueue.front();
+            mQueue.pop();
+        }
+        {
+            char name[64];
+            snprintf(name, sizeof(name), "waiting for frame %lu",
+                     static_cast<unsigned long>(entry.mFrameNum));
+            ATRACE_NAME(name);
+            mEngine->waitSync(entry.mSync, 0);
+        }
+    }
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
new file mode 100644
index 0000000..de793c2
--- /dev/null
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2013 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 SF_GLESRENDERENGINE_H_
+#define SF_GLESRENDERENGINE_H_
+
+#include <android-base/thread_annotations.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/private/Description.h>
+
+#define EGL_NO_CONFIG ((EGLConfig)0)
+
+namespace android {
+
+namespace renderengine {
+
+class Mesh;
+class Texture;
+
+namespace gl {
+
+class GLImage;
+
+class GLESRenderEngine : public impl::RenderEngine {
+public:
+    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
+                                                    uint32_t imageCacheSize);
+    static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
+
+    GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
+                     EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
+                     EGLContext protectedContext, EGLSurface protectedDummy,
+                     uint32_t imageCacheSize);
+    ~GLESRenderEngine() override EXCLUDES(mRenderingMutex);
+
+    std::unique_ptr<Framebuffer> createFramebuffer() override;
+    std::unique_ptr<Image> createImage() override;
+
+    void primeCache() const override;
+    bool isCurrent() const override;
+    base::unique_fd flush() override;
+    bool finish() override;
+    bool waitFence(base::unique_fd fenceFd) override;
+    void clearWithColor(float red, float green, float blue, float alpha) override;
+    void fillRegionWithColor(const Region& region, float red, float green, float blue,
+                             float alpha) override;
+    void genTextures(size_t count, uint32_t* names) override;
+    void deleteTextures(size_t count, uint32_t const* names) override;
+    void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+    status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+                                       const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
+    status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
+    void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
+    status_t bindFrameBuffer(Framebuffer* framebuffer) override;
+    void unbindFrameBuffer(Framebuffer* framebuffer) override;
+    void checkErrors() const override;
+
+    bool isProtected() const override { return mInProtectedContext; }
+    bool supportsProtectedContent() const override;
+    bool useProtectedContext(bool useProtectedContext) override;
+    status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
+                        ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+                        base::unique_fd&& bufferFence, base::unique_fd* drawFence)
+            EXCLUDES(mRenderingMutex) override;
+
+    // internal to RenderEngine
+    EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
+    EGLConfig getEGLConfig() const { return mEGLConfig; }
+    // Creates an output image for rendering to
+    EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                                               bool useFramebufferCache);
+
+    // Test-only methods
+    // Returns true iff mImageCache contains an image keyed by bufferId
+    bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex);
+    // Returns true iff mFramebufferImageCache contains an image keyed by bufferId
+    bool isFramebufferImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex);
+
+protected:
+    Framebuffer* getFramebufferForDrawing() override;
+    void dump(std::string& result) override;
+    void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+                                  ui::Transform::orientation_flags rotation) override;
+    void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                            const half4& color, float cornerRadius) override;
+    void setupLayerTexturing(const Texture& texture) override;
+    void setupLayerBlackedOut() override;
+    void setupFillWithColor(float r, float g, float b, float a) override;
+    void setColorTransform(const mat4& colorTransform) override;
+    void disableTexturing() override;
+    void disableBlending() override;
+    void setupCornerRadiusCropSize(float width, float height) override;
+
+    // HDR and color management related functions and state
+    void setSourceY410BT2020(bool enable) override;
+    void setSourceDataSpace(ui::Dataspace source) override;
+    void setOutputDataSpace(ui::Dataspace dataspace) override;
+    void setDisplayMaxLuminance(const float maxLuminance) override;
+
+    // drawing
+    void drawMesh(const Mesh& mesh) override;
+
+    size_t getMaxTextureSize() const override;
+    size_t getMaxViewportDims() const override;
+
+private:
+    enum GlesVersion {
+        GLES_VERSION_1_0 = 0x10000,
+        GLES_VERSION_1_1 = 0x10001,
+        GLES_VERSION_2_0 = 0x20000,
+        GLES_VERSION_3_0 = 0x30000,
+    };
+
+    static GlesVersion parseGlesVersion(const char* str);
+    static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
+                                       EGLContext shareContext, bool useContextPriority,
+                                       Protection protection);
+    static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                   int hwcFormat, Protection protection);
+    void setScissor(const Rect& region);
+    void disableScissor();
+    bool waitSync(EGLSyncKHR sync, EGLint flags);
+
+    // A data space is considered HDR data space if it has BT2020 color space
+    // with PQ or HLG transfer function.
+    bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
+    bool needsXYZTransformMatrix() const;
+    // Defines the viewport, and sets the projection matrix to the projection
+    // defined by the clip.
+    void setViewportAndProjection(Rect viewport, Rect clip);
+    // Evicts stale images from the buffer cache.
+    void evictImages(const std::vector<LayerSettings>& layers);
+    // Computes the cropping window for the layer and sets up cropping
+    // coordinates for the mesh.
+    FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
+
+    // We do a special handling for rounded corners when it's possible to turn off blending
+    // for the majority of the layer. The rounded corners needs to turn on blending such that
+    // we can set the alpha value correctly, however, only the corners need this, and since
+    // blending is an expensive operation, we want to turn off blending when it's not necessary.
+    void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer,
+                              const Mesh& mesh);
+
+    EGLDisplay mEGLDisplay;
+    EGLConfig mEGLConfig;
+    EGLContext mEGLContext;
+    EGLSurface mDummySurface;
+    EGLContext mProtectedEGLContext;
+    EGLSurface mProtectedDummySurface;
+    GLuint mProtectedTexName;
+    GLint mMaxViewportDims[2];
+    GLint mMaxTextureSize;
+    GLuint mVpWidth;
+    GLuint mVpHeight;
+    Description mState;
+
+    mat4 mSrgbToXyz;
+    mat4 mDisplayP3ToXyz;
+    mat4 mBt2020ToXyz;
+    mat4 mXyzToSrgb;
+    mat4 mXyzToDisplayP3;
+    mat4 mXyzToBt2020;
+    mat4 mSrgbToDisplayP3;
+    mat4 mSrgbToBt2020;
+    mat4 mDisplayP3ToSrgb;
+    mat4 mDisplayP3ToBt2020;
+    mat4 mBt2020ToSrgb;
+    mat4 mBt2020ToDisplayP3;
+
+    bool mInProtectedContext = false;
+    // If set to true, then enables tracing flush() and finish() to systrace.
+    bool mTraceGpuCompletion = false;
+    // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
+    // the last recently used buffer should be kicked out.
+    uint32_t mFramebufferImageCacheSize = 0;
+
+    // Cache of output images, keyed by corresponding GraphicBuffer ID.
+    std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache;
+
+    // Current dataspace of layer being rendered
+    ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
+
+    // Current output dataspace of the render engine
+    ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
+
+    // Whether device supports color management, currently color management
+    // supports sRGB, DisplayP3 color spaces.
+    const bool mUseColorManagement = false;
+
+    // Cache of GL images that we'll store per GraphicBuffer ID
+    std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache GUARDED_BY(mRenderingMutex);
+    // Mutex guarding rendering operations, so that:
+    // 1. GL operations aren't interleaved, and
+    // 2. Internal state related to rendering that is potentially modified by
+    // multiple threads is guaranteed thread-safe.
+    std::mutex mRenderingMutex;
+
+    // See bindExternalTextureBuffer above, but requiring that mRenderingMutex
+    // is held.
+    status_t bindExternalTextureBufferLocked(uint32_t texName, const sp<GraphicBuffer>& buffer,
+                                             const sp<Fence>& fence) REQUIRES(mRenderingMutex);
+    // See cacheExternalTextureBuffer above, but requiring that mRenderingMutex
+    // is held.
+    status_t cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer)
+            REQUIRES(mRenderingMutex);
+
+    std::unique_ptr<Framebuffer> mDrawingBuffer;
+
+    class FlushTracer {
+    public:
+        FlushTracer(GLESRenderEngine* engine);
+        ~FlushTracer();
+        void queueSync(EGLSyncKHR sync) EXCLUDES(mMutex);
+
+        struct QueueEntry {
+            EGLSyncKHR mSync = nullptr;
+            uint64_t mFrameNum = 0;
+        };
+
+    private:
+        void loop();
+        GLESRenderEngine* const mEngine;
+        std::thread mThread;
+        std::condition_variable_any mCondition;
+        std::mutex mMutex;
+        std::queue<QueueEntry> mQueue GUARDED_BY(mMutex);
+        uint64_t mFramesQueued GUARDED_BY(mMutex) = 0;
+        bool mRunning = true;
+    };
+    friend class FlushTracer;
+    std::unique_ptr<FlushTracer> mFlushTracer;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_GLESRENDERENGINE_H_ */
diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
new file mode 100644
index 0000000..2924b0e
--- /dev/null
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010 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 "GLExtensions.h"
+
+#include <string>
+#include <unordered_set>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::GLExtensions)
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+namespace {
+
+class ExtensionSet {
+public:
+    ExtensionSet(const char* extensions) {
+        char const* curr = extensions;
+        char const* head = curr;
+        do {
+            head = strchr(curr, ' ');
+            size_t len = head ? head - curr : strlen(curr);
+            if (len > 0) {
+                mExtensions.emplace(curr, len);
+            }
+            curr = head + 1;
+        } while (head);
+    }
+
+    bool hasExtension(const char* extension) const { return mExtensions.count(extension) > 0; }
+
+private:
+    std::unordered_set<std::string> mExtensions;
+};
+
+} // anonymous namespace
+
+void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
+                                     GLubyte const* version, GLubyte const* extensions) {
+    mVendor = (char const*)vendor;
+    mRenderer = (char const*)renderer;
+    mVersion = (char const*)version;
+    mExtensions = (char const*)extensions;
+
+    ExtensionSet extensionSet(mExtensions.c_str());
+    if (extensionSet.hasExtension("GL_EXT_protected_textures")) {
+        mHasProtectedTexture = true;
+    }
+}
+
+char const* GLExtensions::getVendor() const {
+    return mVendor.string();
+}
+
+char const* GLExtensions::getRenderer() const {
+    return mRenderer.string();
+}
+
+char const* GLExtensions::getVersion() const {
+    return mVersion.string();
+}
+
+char const* GLExtensions::getExtensions() const {
+    return mExtensions.string();
+}
+
+void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
+    mEGLVersion = eglVersion;
+    mEGLExtensions = eglExtensions;
+
+    ExtensionSet extensionSet(eglExtensions);
+
+    // EGL_ANDROIDX_no_config_context is an experimental extension with no
+    // written specification. It will be replaced by something more formal.
+    // SurfaceFlinger is using it to allow a single EGLContext to render to
+    // both a 16-bit primary display framebuffer and a 32-bit virtual display
+    // framebuffer.
+    //
+    // EGL_KHR_no_config_context is official extension to allow creating a
+    // context that works with any surface of a display.
+    if (extensionSet.hasExtension("EGL_ANDROIDX_no_config_context") ||
+        extensionSet.hasExtension("EGL_KHR_no_config_context")) {
+        mHasNoConfigContext = true;
+    }
+
+    if (extensionSet.hasExtension("EGL_ANDROID_native_fence_sync")) {
+        mHasNativeFenceSync = true;
+    }
+    if (extensionSet.hasExtension("EGL_KHR_fence_sync")) {
+        mHasFenceSync = true;
+    }
+    if (extensionSet.hasExtension("EGL_KHR_wait_sync")) {
+        mHasWaitSync = true;
+    }
+    if (extensionSet.hasExtension("EGL_EXT_protected_content")) {
+        mHasProtectedContent = true;
+    }
+    if (extensionSet.hasExtension("EGL_IMG_context_priority")) {
+        mHasContextPriority = true;
+    }
+    if (extensionSet.hasExtension("EGL_KHR_surfaceless_context")) {
+        mHasSurfacelessContext = true;
+    }
+}
+
+char const* GLExtensions::getEGLVersion() const {
+    return mEGLVersion.string();
+}
+
+char const* GLExtensions::getEGLExtensions() const {
+    return mEGLExtensions.string();
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
new file mode 100644
index 0000000..ef00009
--- /dev/null
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 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_SF_GLEXTENSION_H
+#define ANDROID_SF_GLEXTENSION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLExtensions : public Singleton<GLExtensions> {
+public:
+    bool hasNoConfigContext() const { return mHasNoConfigContext; }
+    bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
+    bool hasFenceSync() const { return mHasFenceSync; }
+    bool hasWaitSync() const { return mHasWaitSync; }
+    bool hasProtectedContent() const { return mHasProtectedContent; }
+    bool hasContextPriority() const { return mHasContextPriority; }
+    bool hasSurfacelessContext() const { return mHasSurfacelessContext; }
+    bool hasProtectedTexture() const { return mHasProtectedTexture; }
+
+    void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
+                           GLubyte const* extensions);
+    char const* getVendor() const;
+    char const* getRenderer() const;
+    char const* getVersion() const;
+    char const* getExtensions() const;
+
+    void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
+    char const* getEGLVersion() const;
+    char const* getEGLExtensions() const;
+
+protected:
+    GLExtensions() = default;
+
+private:
+    friend class Singleton<GLExtensions>;
+
+    bool mHasNoConfigContext = false;
+    bool mHasNativeFenceSync = false;
+    bool mHasFenceSync = false;
+    bool mHasWaitSync = false;
+    bool mHasProtectedContent = false;
+    bool mHasContextPriority = false;
+    bool mHasSurfacelessContext = false;
+    bool mHasProtectedTexture = false;
+
+    String8 mVendor;
+    String8 mRenderer;
+    String8 mVersion;
+    String8 mExtensions;
+    String8 mEGLVersion;
+    String8 mEGLExtensions;
+
+    GLExtensions(const GLExtensions&);
+    GLExtensions& operator=(const GLExtensions&);
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
+
+#endif // ANDROID_SF_GLEXTENSION_H
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
new file mode 100644
index 0000000..dacf8d3
--- /dev/null
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GLFramebuffer.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <nativebase/nativebase.h>
+#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine)
+      : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
+    glGenTextures(1, &mTextureName);
+    glGenFramebuffers(1, &mFramebufferName);
+}
+
+GLFramebuffer::~GLFramebuffer() {
+    glDeleteFramebuffers(1, &mFramebufferName);
+    glDeleteTextures(1, &mTextureName);
+}
+
+bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                                          const bool useFramebufferCache) {
+    ATRACE_CALL();
+    if (mEGLImage != EGL_NO_IMAGE_KHR) {
+        if (!usingFramebufferCache) {
+            eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+        }
+        mEGLImage = EGL_NO_IMAGE_KHR;
+        mBufferWidth = 0;
+        mBufferHeight = 0;
+    }
+
+    if (nativeBuffer) {
+        mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected,
+                                                           useFramebufferCache);
+        if (mEGLImage == EGL_NO_IMAGE_KHR) {
+            return false;
+        }
+        usingFramebufferCache = useFramebufferCache;
+        mBufferWidth = nativeBuffer->width;
+        mBufferHeight = nativeBuffer->height;
+    }
+    return true;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
new file mode 100644
index 0000000..b7650bb
--- /dev/null
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <renderengine/Framebuffer.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLESRenderEngine;
+
+class GLFramebuffer : public renderengine::Framebuffer {
+public:
+    explicit GLFramebuffer(GLESRenderEngine& engine);
+    ~GLFramebuffer() override;
+
+    bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                               const bool useFramebufferCache) override;
+    EGLImageKHR getEGLImage() const { return mEGLImage; }
+    uint32_t getTextureName() const { return mTextureName; }
+    uint32_t getFramebufferName() const { return mFramebufferName; }
+    int32_t getBufferHeight() const { return mBufferHeight; }
+    int32_t getBufferWidth() const { return mBufferWidth; }
+
+private:
+    GLESRenderEngine& mEngine;
+    EGLDisplay mEGLDisplay;
+    EGLImageKHR mEGLImage;
+    bool usingFramebufferCache = false;
+    uint32_t mTextureName, mFramebufferName;
+
+    int32_t mBufferHeight = 0;
+    int32_t mBufferWidth = 0;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
new file mode 100644
index 0000000..77e648e
--- /dev/null
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GLImage.h"
+
+#include <vector>
+
+#include <log/log.h>
+#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
+#include "GLExtensions.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+static std::vector<EGLint> buildAttributeList(bool isProtected) {
+    std::vector<EGLint> attrs;
+    attrs.reserve(16);
+
+    attrs.push_back(EGL_IMAGE_PRESERVED_KHR);
+    attrs.push_back(EGL_TRUE);
+
+    if (isProtected && GLExtensions::getInstance().hasProtectedContent()) {
+        attrs.push_back(EGL_PROTECTED_CONTENT_EXT);
+        attrs.push_back(EGL_TRUE);
+    }
+
+    attrs.push_back(EGL_NONE);
+
+    return attrs;
+}
+
+GLImage::GLImage(const GLESRenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+GLImage::~GLImage() {
+    setNativeWindowBuffer(nullptr, false);
+}
+
+bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
+    ATRACE_CALL();
+    if (mEGLImage != EGL_NO_IMAGE_KHR) {
+        if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
+            ALOGE("failed to destroy image: %#x", eglGetError());
+        }
+        mEGLImage = EGL_NO_IMAGE_KHR;
+    }
+
+    if (buffer) {
+        std::vector<EGLint> attrs = buildAttributeList(isProtected);
+        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                      static_cast<EGLClientBuffer>(buffer), attrs.data());
+        if (mEGLImage == EGL_NO_IMAGE_KHR) {
+            ALOGE("failed to create EGLImage: %#x", eglGetError());
+            return false;
+        }
+        mProtected = isProtected;
+    }
+
+    return true;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h
new file mode 100644
index 0000000..59d6ce3
--- /dev/null
+++ b/libs/renderengine/gl/GLImage.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <android-base/macros.h>
+#include <renderengine/Image.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLESRenderEngine;
+
+class GLImage : public renderengine::Image {
+public:
+    explicit GLImage(const GLESRenderEngine& engine);
+    ~GLImage() override;
+
+    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
+
+    EGLImageKHR getEGLImage() const { return mEGLImage; }
+    bool isProtected() const { return mProtected; }
+
+private:
+    EGLDisplay mEGLDisplay;
+    EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+    bool mProtected = false;
+
+    DISALLOW_COPY_AND_ASSIGN(GLImage);
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
new file mode 100644
index 0000000..fe9d909
--- /dev/null
+++ b/libs/renderengine/gl/Program.cpp
@@ -0,0 +1,153 @@
+/*Gluint
+ * Copyright 2013 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 "Program.h"
+
+#include <stdint.h>
+
+#include <log/log.h>
+#include <math/mat4.h>
+#include <utils/String8.h>
+#include "ProgramCache.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
+      : mInitialized(false) {
+    GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
+    GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
+    GLuint programId = glCreateProgram();
+    glAttachShader(programId, vertexId);
+    glAttachShader(programId, fragmentId);
+    glBindAttribLocation(programId, position, "position");
+    glBindAttribLocation(programId, texCoords, "texCoords");
+    glBindAttribLocation(programId, cropCoords, "cropCoords");
+    glLinkProgram(programId);
+
+    GLint status;
+    glGetProgramiv(programId, GL_LINK_STATUS, &status);
+    if (status != GL_TRUE) {
+        ALOGE("Error while linking shaders:");
+        GLint infoLen = 0;
+        glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen);
+        if (infoLen > 1) {
+            GLchar log[infoLen];
+            glGetProgramInfoLog(programId, infoLen, 0, &log[0]);
+            ALOGE("%s", log);
+        }
+        glDetachShader(programId, vertexId);
+        glDetachShader(programId, fragmentId);
+        glDeleteShader(vertexId);
+        glDeleteShader(fragmentId);
+        glDeleteProgram(programId);
+    } else {
+        mProgram = programId;
+        mVertexShader = vertexId;
+        mFragmentShader = fragmentId;
+        mInitialized = true;
+        mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
+        mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
+        mSamplerLoc = glGetUniformLocation(programId, "sampler");
+        mColorLoc = glGetUniformLocation(programId, "color");
+        mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
+        mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix");
+        mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix");
+        mCornerRadiusLoc = glGetUniformLocation(programId, "cornerRadius");
+        mCropCenterLoc = glGetUniformLocation(programId, "cropCenter");
+
+        // set-up the default values for our uniforms
+        glUseProgram(programId);
+        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray());
+        glEnableVertexAttribArray(0);
+    }
+}
+
+bool Program::isValid() const {
+    return mInitialized;
+}
+
+void Program::use() {
+    glUseProgram(mProgram);
+}
+
+GLuint Program::getAttrib(const char* name) const {
+    // TODO: maybe use a local cache
+    return glGetAttribLocation(mProgram, name);
+}
+
+GLint Program::getUniform(const char* name) const {
+    // TODO: maybe use a local cache
+    return glGetUniformLocation(mProgram, name);
+}
+
+GLuint Program::buildShader(const char* source, GLenum type) {
+    GLuint shader = glCreateShader(type);
+    glShaderSource(shader, 1, &source, 0);
+    glCompileShader(shader);
+    GLint status;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+    if (status != GL_TRUE) {
+        // Some drivers return wrong values for GL_INFO_LOG_LENGTH
+        // use a fixed size instead
+        GLchar log[512];
+        glGetShaderInfoLog(shader, sizeof(log), 0, log);
+        ALOGE("Error while compiling shader: \n%s\n%s", source, log);
+        glDeleteShader(shader);
+        return 0;
+    }
+    return shader;
+}
+
+void Program::setUniforms(const Description& desc) {
+    // TODO: we should have a mechanism here to not always reset uniforms that
+    // didn't change for this program.
+
+    if (mSamplerLoc >= 0) {
+        glUniform1i(mSamplerLoc, 0);
+        glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.texture.getMatrix().asArray());
+    }
+    if (mColorLoc >= 0) {
+        const float color[4] = {desc.color.r, desc.color.g, desc.color.b, desc.color.a};
+        glUniform4fv(mColorLoc, 1, color);
+    }
+    if (mInputTransformMatrixLoc >= 0) {
+        mat4 inputTransformMatrix = desc.inputTransformMatrix;
+        glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
+    }
+    if (mOutputTransformMatrixLoc >= 0) {
+        // The output transform matrix and color matrix can be combined as one matrix
+        // that is applied right before applying OETF.
+        mat4 outputTransformMatrix = desc.colorMatrix * desc.outputTransformMatrix;
+        glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE, outputTransformMatrix.asArray());
+    }
+    if (mDisplayMaxLuminanceLoc >= 0) {
+        glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance);
+    }
+    if (mCornerRadiusLoc >= 0) {
+        glUniform1f(mCornerRadiusLoc, desc.cornerRadius);
+    }
+    if (mCropCenterLoc >= 0) {
+        glUniform2f(mCropCenterLoc, desc.cropSize.x / 2.0f, desc.cropSize.y / 2.0f);
+    }
+    // these uniforms are always present
+    glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray());
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h
new file mode 100644
index 0000000..bc9cf08
--- /dev/null
+++ b/libs/renderengine/gl/Program.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2013 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 SF_RENDER_ENGINE_PROGRAM_H
+#define SF_RENDER_ENGINE_PROGRAM_H
+
+#include <stdint.h>
+
+#include <GLES2/gl2.h>
+#include <renderengine/private/Description.h>
+#include "ProgramCache.h"
+
+namespace android {
+
+class String8;
+
+namespace renderengine {
+namespace gl {
+
+/*
+ * Abstracts a GLSL program comprising a vertex and fragment shader
+ */
+class Program {
+public:
+    // known locations for position and texture coordinates
+    enum {
+        /* position of each vertex for vertex shader */
+        position = 0,
+
+        /* UV coordinates for texture mapping */
+        texCoords = 1,
+
+        /* Crop coordinates, in pixels */
+        cropCoords = 2
+    };
+
+    Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
+    ~Program() = default;
+
+    /* whether this object is usable */
+    bool isValid() const;
+
+    /* Binds this program to the GLES context */
+    void use();
+
+    /* Returns the location of the specified attribute */
+    GLuint getAttrib(const char* name) const;
+
+    /* Returns the location of the specified uniform */
+    GLint getUniform(const char* name) const;
+
+    /* set-up uniforms from the description */
+    void setUniforms(const Description& desc);
+
+private:
+    GLuint buildShader(const char* source, GLenum type);
+
+    // whether the initialization succeeded
+    bool mInitialized;
+
+    // Name of the OpenGL program and shaders
+    GLuint mProgram;
+    GLuint mVertexShader;
+    GLuint mFragmentShader;
+
+    /* location of the projection matrix uniform */
+    GLint mProjectionMatrixLoc;
+
+    /* location of the texture matrix uniform */
+    GLint mTextureMatrixLoc;
+
+    /* location of the sampler uniform */
+    GLint mSamplerLoc;
+
+    /* location of the color uniform */
+    GLint mColorLoc;
+
+    /* location of display luminance uniform */
+    GLint mDisplayMaxLuminanceLoc;
+
+    /* location of transform matrix */
+    GLint mInputTransformMatrixLoc;
+    GLint mOutputTransformMatrixLoc;
+
+    /* location of corner radius uniform */
+    GLint mCornerRadiusLoc;
+
+    /* location of surface crop origin uniform, for rounded corner clipping */
+    GLint mCropCenterLoc;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
new file mode 100644
index 0000000..d242677
--- /dev/null
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -0,0 +1,737 @@
+/*
+ * Copyright 2013 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "ProgramCache.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <log/log.h>
+#include <renderengine/private/Description.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+#include "Program.h"
+
+ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::ProgramCache)
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+/*
+ * A simple formatter class to automatically add the endl and
+ * manage the indentation.
+ */
+
+class Formatter;
+static Formatter& indent(Formatter& f);
+static Formatter& dedent(Formatter& f);
+
+class Formatter {
+    String8 mString;
+    int mIndent;
+    typedef Formatter& (*FormaterManipFunc)(Formatter&);
+    friend Formatter& indent(Formatter& f);
+    friend Formatter& dedent(Formatter& f);
+
+public:
+    Formatter() : mIndent(0) {}
+
+    String8 getString() const { return mString; }
+
+    friend Formatter& operator<<(Formatter& out, const char* in) {
+        for (int i = 0; i < out.mIndent; i++) {
+            out.mString.append("    ");
+        }
+        out.mString.append(in);
+        out.mString.append("\n");
+        return out;
+    }
+    friend inline Formatter& operator<<(Formatter& out, const String8& in) {
+        return operator<<(out, in.string());
+    }
+    friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
+        return (*func)(to);
+    }
+};
+Formatter& indent(Formatter& f) {
+    f.mIndent++;
+    return f;
+}
+Formatter& dedent(Formatter& f) {
+    f.mIndent--;
+    return f;
+}
+
+void ProgramCache::primeCache(EGLContext context, bool useColorManagement) {
+    auto& cache = mCaches[context];
+    uint32_t shaderCount = 0;
+    uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK
+        | Key::ROUNDED_CORNERS_MASK;
+    // Prime the cache for all combinations of the above masks,
+    // leaving off the experimental color matrix mask options.
+
+    nsecs_t timeBefore = systemTime();
+    for (uint32_t keyVal = 0; keyVal <= keyMask; keyVal++) {
+        Key shaderKey;
+        shaderKey.set(keyMask, keyVal);
+        uint32_t tex = shaderKey.getTextureTarget();
+        if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
+            continue;
+        }
+        if (cache.count(shaderKey) == 0) {
+            cache.emplace(shaderKey, generateProgram(shaderKey));
+            shaderCount++;
+        }
+    }
+
+    // Prime for sRGB->P3 conversion
+    if (useColorManagement) {
+        Key shaderKey;
+        shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK |
+                              Key::OUTPUT_TF_MASK,
+                      Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB |
+                              Key::OUTPUT_TF_SRGB);
+        for (int i = 0; i < 16; i++) {
+            shaderKey.set(Key::OPACITY_MASK,
+                          (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
+            shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
+
+            // Cache rounded corners
+            shaderKey.set(Key::ROUNDED_CORNERS_MASK,
+                          (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF);
+
+            // Cache texture off option for window transition
+            shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF);
+            if (cache.count(shaderKey) == 0) {
+                cache.emplace(shaderKey, generateProgram(shaderKey));
+                shaderCount++;
+            }
+        }
+    }
+
+    nsecs_t timeAfter = systemTime();
+    float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
+    ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs);
+}
+
+ProgramCache::Key ProgramCache::computeKey(const Description& description) {
+    Key needs;
+    needs.set(Key::TEXTURE_MASK,
+              !description.textureEnabled
+                      ? Key::TEXTURE_OFF
+                      : description.texture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES
+                              ? Key::TEXTURE_EXT
+                              : description.texture.getTextureTarget() == GL_TEXTURE_2D
+                                      ? Key::TEXTURE_2D
+                                      : Key::TEXTURE_OFF)
+            .set(Key::ALPHA_MASK, (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
+            .set(Key::BLEND_MASK,
+                 description.isPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
+            .set(Key::OPACITY_MASK,
+                 description.isOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
+            .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK,
+                 description.hasInputTransformMatrix()
+                         ? Key::INPUT_TRANSFORM_MATRIX_ON : Key::INPUT_TRANSFORM_MATRIX_OFF)
+            .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK,
+                 description.hasOutputTransformMatrix() || description.hasColorMatrix()
+                         ? Key::OUTPUT_TRANSFORM_MATRIX_ON
+                         : Key::OUTPUT_TRANSFORM_MATRIX_OFF)
+            .set(Key::ROUNDED_CORNERS_MASK,
+                 description.cornerRadius > 0
+                         ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF);
+
+    needs.set(Key::Y410_BT2020_MASK,
+              description.isY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
+
+    if (needs.hasTransformMatrix() ||
+        (description.inputTransferFunction != description.outputTransferFunction)) {
+        switch (description.inputTransferFunction) {
+            case Description::TransferFunction::LINEAR:
+            default:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR);
+                break;
+            case Description::TransferFunction::SRGB:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB);
+                break;
+            case Description::TransferFunction::ST2084:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084);
+                break;
+            case Description::TransferFunction::HLG:
+                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG);
+                break;
+        }
+
+        switch (description.outputTransferFunction) {
+            case Description::TransferFunction::LINEAR:
+            default:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR);
+                break;
+            case Description::TransferFunction::SRGB:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB);
+                break;
+            case Description::TransferFunction::ST2084:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084);
+                break;
+            case Description::TransferFunction::HLG:
+                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG);
+                break;
+        }
+    }
+
+    return needs;
+}
+
+// Generate EOTF that converts signal values to relative display light,
+// both normalized to [0, 1].
+void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) {
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_SRGB:
+            fs << R"__SHADER__(
+                float EOTF_sRGB(float srgb) {
+                    return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+                }
+
+                vec3 EOTF_sRGB(const vec3 srgb) {
+                    return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+                }
+
+                vec3 EOTF(const vec3 srgb) {
+                    return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                vec3 EOTF(const highp vec3 color) {
+                    const highp float m1 = (2610.0 / 4096.0) / 4.0;
+                    const highp float m2 = (2523.0 / 4096.0) * 128.0;
+                    const highp float c1 = (3424.0 / 4096.0);
+                    const highp float c2 = (2413.0 / 4096.0) * 32.0;
+                    const highp float c3 = (2392.0 / 4096.0) * 32.0;
+
+                    highp vec3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / vec3(m2));
+                    tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
+                    return pow(tmp, 1.0 / vec3(m1));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp float EOTF_channel(const highp float channel) {
+                    const highp float a = 0.17883277;
+                    const highp float b = 0.28466892;
+                    const highp float c = 0.55991073;
+                    return channel <= 0.5 ? channel * channel / 3.0 :
+                            (exp((channel - c) / a) + b) / 12.0;
+                }
+
+                vec3 EOTF(const highp vec3 color) {
+                    return vec3(EOTF_channel(color.r), EOTF_channel(color.g),
+                            EOTF_channel(color.b));
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                vec3 EOTF(const vec3 linear) {
+                    return linear;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) {
+    // Convert relative light to absolute light.
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                highp vec3 ScaleLuminance(highp vec3 color) {
+                    return color * 10000.0;
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp vec3 ScaleLuminance(highp vec3 color) {
+                    // The formula is:
+                    // alpha * pow(Y, gamma - 1.0) * color + beta;
+                    // where alpha is 1000.0, gamma is 1.2, beta is 0.0.
+                    return color * 1000.0 * pow(color.y, 0.2);
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                highp vec3 ScaleLuminance(highp vec3 color) {
+                    return color * displayMaxLuminance;
+                }
+            )__SHADER__";
+            break;
+    }
+
+    // Tone map absolute light to display luminance range.
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_ST2084:
+        case Key::INPUT_TF_HLG:
+            switch (needs.getOutputTF()) {
+                case Key::OUTPUT_TF_HLG:
+                    // Right now when mixed PQ and HLG contents are presented,
+                    // HLG content will always be converted to PQ. However, for
+                    // completeness, we simply clamp the value to [0.0, 1000.0].
+                    fs << R"__SHADER__(
+                        highp vec3 ToneMap(highp vec3 color) {
+                            return clamp(color, 0.0, 1000.0);
+                        }
+                    )__SHADER__";
+                    break;
+                case Key::OUTPUT_TF_ST2084:
+                    fs << R"__SHADER__(
+                        highp vec3 ToneMap(highp vec3 color) {
+                            return color;
+                        }
+                    )__SHADER__";
+                    break;
+                default:
+                    fs << R"__SHADER__(
+                        highp vec3 ToneMap(highp vec3 color) {
+                            const float maxMasteringLumi = 1000.0;
+                            const float maxContentLumi = 1000.0;
+                            const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
+                            float maxOutLumi = displayMaxLuminance;
+
+                            float nits = color.y;
+
+                            // clamp to max input luminance
+                            nits = clamp(nits, 0.0, maxInLumi);
+
+                            // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+                            if (maxInLumi <= maxOutLumi) {
+                                return color * (maxOutLumi / maxInLumi);
+                            } else {
+                                // three control points
+                                const float x0 = 10.0;
+                                const float y0 = 17.0;
+                                float x1 = maxOutLumi * 0.75;
+                                float y1 = x1;
+                                float x2 = x1 + (maxInLumi - x1) / 2.0;
+                                float y2 = y1 + (maxOutLumi - y1) * 0.75;
+
+                                // horizontal distances between the last three control points
+                                float h12 = x2 - x1;
+                                float h23 = maxInLumi - x2;
+                                // tangents at the last three control points
+                                float m1 = (y2 - y1) / h12;
+                                float m3 = (maxOutLumi - y2) / h23;
+                                float m2 = (m1 + m3) / 2.0;
+
+                                if (nits < x0) {
+                                    // scale [0.0, x0] to [0.0, y0] linearly
+                                    float slope = y0 / x0;
+                                    return color * slope;
+                                } else if (nits < x1) {
+                                    // scale [x0, x1] to [y0, y1] linearly
+                                    float slope = (y1 - y0) / (x1 - x0);
+                                    nits = y0 + (nits - x0) * slope;
+                                } else if (nits < x2) {
+                                    // scale [x1, x2] to [y1, y2] using Hermite interp
+                                    float t = (nits - x1) / h12;
+                                    nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
+                                            (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+                                } else {
+                                    // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
+                                    float t = (nits - x2) / h23;
+                                    nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
+                                            (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
+                                }
+                            }
+
+                            // color.y is greater than x0 and is thus non-zero
+                            return color * (nits / color.y);
+                        }
+                    )__SHADER__";
+                    break;
+            }
+            break;
+        default:
+            // inverse tone map; the output luminance can be up to maxOutLumi.
+            fs << R"__SHADER__(
+                highp vec3 ToneMap(highp vec3 color) {
+                    const float maxOutLumi = 3000.0;
+
+                    const float x0 = 5.0;
+                    const float y0 = 2.5;
+                    float x1 = displayMaxLuminance * 0.7;
+                    float y1 = maxOutLumi * 0.15;
+                    float x2 = displayMaxLuminance * 0.9;
+                    float y2 = maxOutLumi * 0.45;
+                    float x3 = displayMaxLuminance;
+                    float y3 = maxOutLumi;
+
+                    float c1 = y1 / 3.0;
+                    float c2 = y2 / 2.0;
+                    float c3 = y3 / 1.5;
+
+                    float nits = color.y;
+
+                    float scale;
+                    if (nits <= x0) {
+                        // scale [0.0, x0] to [0.0, y0] linearly
+                        const float slope = y0 / x0;
+                        return color * slope;
+                    } else if (nits <= x1) {
+                        // scale [x0, x1] to [y0, y1] using a curve
+                        float t = (nits - x0) / (x1 - x0);
+                        nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1;
+                    } else if (nits <= x2) {
+                        // scale [x1, x2] to [y1, y2] using a curve
+                        float t = (nits - x1) / (x2 - x1);
+                        nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2;
+                    } else {
+                        // scale [x2, x3] to [y2, y3] using a curve
+                        float t = (nits - x2) / (x3 - x2);
+                        nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
+                    }
+
+                    // color.y is greater than x0 and is thus non-zero
+                    return color * (nits / color.y);
+                }
+            )__SHADER__";
+            break;
+    }
+
+    // convert absolute light to relative light.
+    switch (needs.getOutputTF()) {
+        case Key::OUTPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                highp vec3 NormalizeLuminance(highp vec3 color) {
+                    return color / 10000.0;
+                }
+            )__SHADER__";
+            break;
+        case Key::OUTPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp vec3 NormalizeLuminance(highp vec3 color) {
+                    return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2);
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                highp vec3 NormalizeLuminance(highp vec3 color) {
+                    return color / displayMaxLuminance;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+// Generate OOTF that modifies the relative scence light to relative display light.
+void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) {
+    if (!needs.needsToneMapping()) {
+        fs << R"__SHADER__(
+            highp vec3 OOTF(const highp vec3 color) {
+                return color;
+            }
+        )__SHADER__";
+    } else {
+        generateToneMappingProcess(fs, needs);
+        fs << R"__SHADER__(
+            highp vec3 OOTF(const highp vec3 color) {
+                return NormalizeLuminance(ToneMap(ScaleLuminance(color)));
+            }
+        )__SHADER__";
+    }
+}
+
+// Generate OETF that converts relative display light to signal values,
+// both normalized to [0, 1]
+void ProgramCache::generateOETF(Formatter& fs, const Key& needs) {
+    switch (needs.getOutputTF()) {
+        case Key::OUTPUT_TF_SRGB:
+            fs << R"__SHADER__(
+                float OETF_sRGB(const float linear) {
+                    return linear <= 0.0031308 ?
+                            linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+                }
+
+                vec3 OETF_sRGB(const vec3 linear) {
+                    return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+                }
+
+                vec3 OETF(const vec3 linear) {
+                    return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+                }
+            )__SHADER__";
+            break;
+        case Key::OUTPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                vec3 OETF(const vec3 linear) {
+                    const highp float m1 = (2610.0 / 4096.0) / 4.0;
+                    const highp float m2 = (2523.0 / 4096.0) * 128.0;
+                    const highp float c1 = (3424.0 / 4096.0);
+                    const highp float c2 = (2413.0 / 4096.0) * 32.0;
+                    const highp float c3 = (2392.0 / 4096.0) * 32.0;
+
+                    highp vec3 tmp = pow(linear, vec3(m1));
+                    tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
+                    return pow(tmp, vec3(m2));
+                }
+            )__SHADER__";
+            break;
+        case Key::OUTPUT_TF_HLG:
+            fs << R"__SHADER__(
+                highp float OETF_channel(const highp float channel) {
+                    const highp float a = 0.17883277;
+                    const highp float b = 0.28466892;
+                    const highp float c = 0.55991073;
+                    return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
+                            a * log(12.0 * channel - b) + c;
+                }
+
+                vec3 OETF(const highp vec3 color) {
+                    return vec3(OETF_channel(color.r), OETF_channel(color.g),
+                            OETF_channel(color.b));
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                vec3 OETF(const vec3 linear) {
+                    return linear;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+String8 ProgramCache::generateVertexShader(const Key& needs) {
+    Formatter vs;
+    if (needs.isTexturing()) {
+        vs << "attribute vec4 texCoords;"
+           << "varying vec2 outTexCoords;";
+    }
+    if (needs.hasRoundedCorners()) {
+        vs << "attribute lowp vec4 cropCoords;";
+        vs << "varying lowp vec2 outCropCoords;";
+    }
+    vs << "attribute vec4 position;"
+       << "uniform mat4 projection;"
+       << "uniform mat4 texture;"
+       << "void main(void) {" << indent << "gl_Position = projection * position;";
+    if (needs.isTexturing()) {
+        vs << "outTexCoords = (texture * texCoords).st;";
+    }
+    if (needs.hasRoundedCorners()) {
+        vs << "outCropCoords = cropCoords.st;";
+    }
+    vs << dedent << "}";
+    return vs.getString();
+}
+
+String8 ProgramCache::generateFragmentShader(const Key& needs) {
+    Formatter fs;
+    if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
+        fs << "#extension GL_OES_EGL_image_external : require";
+    }
+
+    // default precision is required-ish in fragment shaders
+    fs << "precision mediump float;";
+
+    if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
+        fs << "uniform samplerExternalOES sampler;"
+           << "varying vec2 outTexCoords;";
+    } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
+        fs << "uniform sampler2D sampler;"
+           << "varying vec2 outTexCoords;";
+    }
+
+    if (needs.hasRoundedCorners()) {
+        // Rounded corners implementation using a signed distance function.
+        fs << R"__SHADER__(
+            uniform float cornerRadius;
+            uniform vec2 cropCenter;
+            varying vec2 outCropCoords;
+
+            /**
+             * This function takes the current crop coordinates and calculates an alpha value based
+             * on the corner radius and distance from the crop center.
+             */
+            float applyCornerRadius(vec2 cropCoords)
+            {
+                vec2 position = cropCoords - cropCenter;
+                // Scale down the dist vector here, as otherwise large corner
+                // radii can cause floating point issues when computing the norm
+                vec2 dist = (abs(position) - cropCenter + vec2(cornerRadius)) / 16.0;
+                // Once we've found the norm, then scale back up.
+                float plane = length(max(dist, vec2(0.0))) * 16.0;
+                return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0);
+            }
+            )__SHADER__";
+    }
+
+    if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
+        fs << "uniform vec4 color;";
+    }
+
+    if (needs.isY410BT2020()) {
+        fs << R"__SHADER__(
+            vec3 convertY410BT2020(const vec3 color) {
+                const vec3 offset = vec3(0.0625, 0.5, 0.5);
+                const mat3 transform = mat3(
+                    vec3(1.1678,  1.1678, 1.1678),
+                    vec3(   0.0, -0.1878, 2.1481),
+                    vec3(1.6836, -0.6523,   0.0));
+                // Y is in G, U is in R, and V is in B
+                return clamp(transform * (color.grb - offset), 0.0, 1.0);
+            }
+            )__SHADER__";
+    }
+
+    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+        // Currently, display maximum luminance is needed when doing tone mapping.
+        if (needs.needsToneMapping()) {
+            fs << "uniform float displayMaxLuminance;";
+        }
+
+        if (needs.hasInputTransformMatrix()) {
+            fs << "uniform mat4 inputTransformMatrix;";
+            fs << R"__SHADER__(
+                highp vec3 InputTransform(const highp vec3 color) {
+                    return clamp(vec3(inputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
+                }
+            )__SHADER__";
+        } else {
+            fs << R"__SHADER__(
+                highp vec3 InputTransform(const highp vec3 color) {
+                    return color;
+                }
+            )__SHADER__";
+        }
+
+        // the transformation from a wider colorspace to a narrower one can
+        // result in >1.0 or <0.0 pixel values
+        if (needs.hasOutputTransformMatrix()) {
+            fs << "uniform mat4 outputTransformMatrix;";
+            fs << R"__SHADER__(
+                highp vec3 OutputTransform(const highp vec3 color) {
+                    return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
+                }
+            )__SHADER__";
+        } else {
+            fs << R"__SHADER__(
+                highp vec3 OutputTransform(const highp vec3 color) {
+                    return clamp(color, 0.0, 1.0);
+                }
+            )__SHADER__";
+        }
+
+        generateEOTF(fs, needs);
+        generateOOTF(fs, needs);
+        generateOETF(fs, needs);
+    }
+
+    fs << "void main(void) {" << indent;
+    if (needs.isTexturing()) {
+        fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
+        if (needs.isY410BT2020()) {
+            fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);";
+        }
+    } else {
+        fs << "gl_FragColor.rgb = color.rgb;";
+        fs << "gl_FragColor.a = 1.0;";
+    }
+    if (needs.isOpaque()) {
+        fs << "gl_FragColor.a = 1.0;";
+    }
+    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 *= color.a;";
+        } else {
+            fs << "gl_FragColor.a *= color.a;";
+        }
+    }
+
+    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+        if (!needs.isOpaque() && needs.isPremultiplied()) {
+            // un-premultiply if needed before linearization
+            // avoid divide by 0 by adding 0.5/256 to the alpha channel
+            fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
+        }
+        fs << "gl_FragColor.rgb = "
+              "OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
+        if (!needs.isOpaque() && needs.isPremultiplied()) {
+            // and re-premultiply if needed after gamma correction
+            fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
+        }
+    }
+
+    if (needs.hasRoundedCorners()) {
+        if (needs.isPremultiplied()) {
+            fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));";
+        } else {
+            fs << "gl_FragColor.a *= applyCornerRadius(outCropCoords);";
+        }
+    }
+
+    fs << dedent << "}";
+    return fs.getString();
+}
+
+std::unique_ptr<Program> ProgramCache::generateProgram(const Key& needs) {
+    ATRACE_CALL();
+
+    // vertex shader
+    String8 vs = generateVertexShader(needs);
+
+    // fragment shader
+    String8 fs = generateFragmentShader(needs);
+
+    return std::make_unique<Program>(needs, vs.string(), fs.string());
+}
+
+void ProgramCache::useProgram(EGLContext context, const Description& description) {
+    // generate the key for the shader based on the description
+    Key needs(computeKey(description));
+
+    // look-up the program in the cache
+    auto& cache = mCaches[context];
+    auto it = cache.find(needs);
+    if (it == cache.end()) {
+        // we didn't find our program, so generate one...
+        nsecs_t time = systemTime();
+        it = cache.emplace(needs, generateProgram(needs)).first;
+        time = systemTime() - time;
+
+        ALOGV(">>> generated new program for context %p: needs=%08X, time=%u ms (%zu programs)",
+              context, needs.mKey, uint32_t(ns2ms(time)), cache.size());
+    }
+
+    // here we have a suitable program for this description
+    std::unique_ptr<Program>& program = it->second;
+    if (program->isValid()) {
+        program->use();
+        program->setUniforms(description);
+    }
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
new file mode 100644
index 0000000..400ad74
--- /dev/null
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2013 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 SF_RENDER_ENGINE_PROGRAMCACHE_H
+#define SF_RENDER_ENGINE_PROGRAMCACHE_H
+
+#include <memory>
+#include <unordered_map>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <renderengine/private/Description.h>
+#include <utils/Singleton.h>
+#include <utils/TypeHelpers.h>
+
+namespace android {
+
+class String8;
+
+namespace renderengine {
+
+struct Description;
+
+namespace gl {
+
+class Formatter;
+class Program;
+
+/*
+ * This class generates GLSL programs suitable to handle a given
+ * Description. It's responsible for figuring out what to
+ * generate from a Description.
+ * It also maintains a cache of these Programs.
+ */
+class ProgramCache : public Singleton<ProgramCache> {
+public:
+    /*
+     * Key is used to retrieve a Program in the cache.
+     * A Key is generated from a Description.
+     */
+    class Key {
+        friend class ProgramCache;
+        typedef uint32_t key_t;
+        key_t mKey;
+
+    public:
+        enum {
+            BLEND_SHIFT = 0,
+            BLEND_MASK = 1 << BLEND_SHIFT,
+            BLEND_PREMULT = 1 << BLEND_SHIFT,
+            BLEND_NORMAL = 0 << BLEND_SHIFT,
+
+            OPACITY_SHIFT = 1,
+            OPACITY_MASK = 1 << OPACITY_SHIFT,
+            OPACITY_OPAQUE = 1 << OPACITY_SHIFT,
+            OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT,
+
+            ALPHA_SHIFT = 2,
+            ALPHA_MASK = 1 << ALPHA_SHIFT,
+            ALPHA_LT_ONE = 1 << ALPHA_SHIFT,
+            ALPHA_EQ_ONE = 0 << ALPHA_SHIFT,
+
+            TEXTURE_SHIFT = 3,
+            TEXTURE_MASK = 3 << TEXTURE_SHIFT,
+            TEXTURE_OFF = 0 << TEXTURE_SHIFT,
+            TEXTURE_EXT = 1 << TEXTURE_SHIFT,
+            TEXTURE_2D = 2 << TEXTURE_SHIFT,
+
+            ROUNDED_CORNERS_SHIFT = 5,
+            ROUNDED_CORNERS_MASK = 1 << ROUNDED_CORNERS_SHIFT,
+            ROUNDED_CORNERS_OFF = 0 << ROUNDED_CORNERS_SHIFT,
+            ROUNDED_CORNERS_ON = 1 << ROUNDED_CORNERS_SHIFT,
+
+            INPUT_TRANSFORM_MATRIX_SHIFT = 6,
+            INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
+            INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT,
+            INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT,
+
+            OUTPUT_TRANSFORM_MATRIX_SHIFT = 7,
+            OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+            OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+            OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT,
+
+            INPUT_TF_SHIFT = 8,
+            INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
+            INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
+            INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
+            INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
+            INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,
+
+            OUTPUT_TF_SHIFT = 10,
+            OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
+            OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,
+
+            Y410_BT2020_SHIFT = 12,
+            Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
+            Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
+            Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
+        };
+
+        inline Key() : mKey(0) {}
+        inline Key(const Key& rhs) : mKey(rhs.mKey) {}
+
+        inline Key& set(key_t mask, key_t value) {
+            mKey = (mKey & ~mask) | value;
+            return *this;
+        }
+
+        inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
+        inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
+        inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
+        inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
+        inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
+        inline bool hasRoundedCorners() const {
+            return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON;
+        }
+        inline bool hasInputTransformMatrix() const {
+            return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON;
+        }
+        inline bool hasOutputTransformMatrix() const {
+            return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
+        }
+        inline bool hasTransformMatrix() const {
+            return hasInputTransformMatrix() || hasOutputTransformMatrix();
+        }
+        inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
+        inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
+
+        // When HDR and non-HDR contents are mixed, or different types of HDR contents are
+        // mixed, we will do a tone mapping process to tone map the input content to output
+        // content. Currently, the following conversions handled, they are:
+        // * SDR -> HLG
+        // * SDR -> PQ
+        // * HLG -> PQ
+        inline bool needsToneMapping() const {
+            int inputTF = getInputTF();
+            int outputTF = getOutputTF();
+
+            // Return false when converting from SDR to SDR.
+            if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) {
+                return false;
+            }
+            if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) {
+                return false;
+            }
+
+            inputTF >>= Key::INPUT_TF_SHIFT;
+            outputTF >>= Key::OUTPUT_TF_SHIFT;
+            return inputTF != outputTF;
+        }
+        inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
+
+        // for use by std::unordered_map
+
+        bool operator==(const Key& other) const { return mKey == other.mKey; }
+
+        struct Hash {
+            size_t operator()(const Key& key) const { return static_cast<size_t>(key.mKey); }
+        };
+    };
+
+    ProgramCache() = default;
+    ~ProgramCache() = default;
+
+    // Generate shaders to populate the cache
+    void primeCache(const EGLContext context, bool useColorManagement);
+
+    size_t getSize(const EGLContext context) { return mCaches[context].size(); }
+
+    // useProgram lookup a suitable program in the cache or generates one
+    // if none can be found.
+    void useProgram(const EGLContext context, const Description& description);
+
+private:
+    // compute a cache Key from a Description
+    static Key computeKey(const Description& description);
+    // Generate EOTF based from Key.
+    static void generateEOTF(Formatter& fs, const Key& needs);
+    // Generate necessary tone mapping methods for OOTF.
+    static void generateToneMappingProcess(Formatter& fs, const Key& needs);
+    // Generate OOTF based from Key.
+    static void generateOOTF(Formatter& fs, const Key& needs);
+    // Generate OETF based from Key.
+    static void generateOETF(Formatter& fs, const Key& needs);
+    // generates a program from the Key
+    static std::unique_ptr<Program> generateProgram(const Key& needs);
+    // generates the vertex shader from the Key
+    static String8 generateVertexShader(const Key& needs);
+    // generates the fragment shader from the Key
+    static String8 generateFragmentShader(const Key& needs);
+
+    // Key/Value map used for caching Programs. Currently the cache
+    // is never shrunk (and the GL program objects are never deleted).
+    std::unordered_map<EGLContext, std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash>>
+            mCaches;
+};
+
+} // namespace gl
+} // namespace renderengine
+
+ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key)
+
+} // namespace android
+
+#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
new file mode 100644
index 0000000..9c9884a
--- /dev/null
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <math/mat4.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+namespace renderengine {
+
+// DisplaySettings contains the settings that are applicable when drawing all
+// layers for a given display.
+struct DisplaySettings {
+    // Rectangle describing the physical display. We will project from the
+    // logical clip onto this rectangle.
+    Rect physicalDisplay = Rect::INVALID_RECT;
+
+    // Rectangle bounded by the x,y- clipping planes in the logical display, so
+    // that the orthographic projection matrix can be computed. When
+    // constructing this matrix, z-coordinate bound are assumed to be at z=0 and
+    // z=1.
+    Rect clip = Rect::INVALID_RECT;
+
+    // Global transform to apply to all layers.
+    mat4 globalTransform = mat4();
+
+    // Maximum luminance pulled from the display's HDR capabilities.
+    float maxLuminance = 1.0f;
+
+    // Output dataspace that will be populated if wide color gamut is used, or
+    // DataSpace::UNKNOWN otherwise.
+    ui::Dataspace outputDataspace = ui::Dataspace::UNKNOWN;
+
+    // Additional color transform to apply in linear space after transforming
+    // to the output dataspace.
+    mat4 colorTransform = mat4();
+
+    // Region that will be cleared to (0, 0, 0, 1) prior to rendering.
+    // RenderEngine will transform the clearRegion passed in here, by
+    // globalTransform, so that it will be in the same coordinate space as the
+    // rendered layers.
+    Region clearRegion = Region::INVALID_REGION;
+
+    // The orientation of the physical display.
+    uint32_t orientation = ui::Transform::ROT_0;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h
new file mode 100644
index 0000000..6511127
--- /dev/null
+++ b/libs/renderengine/include/renderengine/Framebuffer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+
+class Framebuffer {
+public:
+    virtual ~Framebuffer() = default;
+
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+                                       const bool useFramebufferCache) = 0;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/Image.h b/libs/renderengine/include/renderengine/Image.h
new file mode 100644
index 0000000..3bb4731
--- /dev/null
+++ b/libs/renderengine/include/renderengine/Image.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+struct ANativeWindowBuffer;
+
+namespace android {
+namespace renderengine {
+
+class Image {
+public:
+    virtual ~Image() = default;
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
new file mode 100644
index 0000000..b8bf801
--- /dev/null
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <math/mat4.h>
+#include <math/vec3.h>
+#include <renderengine/Texture.h>
+#include <ui/Fence.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+namespace renderengine {
+
+// Metadata describing the input buffer to render from.
+struct Buffer {
+    // Buffer containing the image that we will render.
+    // If buffer == nullptr, then the rest of the fields in this struct will be
+    // ignored.
+    sp<GraphicBuffer> buffer = nullptr;
+
+    // Fence that will fire when the buffer is ready to be bound.
+    sp<Fence> fence = nullptr;
+
+    // Texture identifier to bind the external texture to.
+    // TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
+    uint32_t textureName = 0;
+
+    // Whether to use filtering when rendering the texture.
+    bool useTextureFiltering = false;
+
+    // Transform matrix to apply to texture coordinates.
+    mat4 textureTransform = mat4();
+
+    // Wheteher to use pre-multiplied alpha
+    bool usePremultipliedAlpha = true;
+
+    // Override flag that alpha for each pixel in the buffer *must* be 1.0.
+    // LayerSettings::alpha is still used if isOpaque==true - this flag only
+    // overrides the alpha channel of the buffer.
+    bool isOpaque = false;
+
+    // HDR color-space setting for Y410.
+    bool isY410BT2020 = false;
+};
+
+// Metadata describing the layer geometry.
+struct Geometry {
+    // Boundaries of the layer.
+    FloatRect boundaries = FloatRect();
+
+    // Transform matrix to apply to mesh coordinates.
+    mat4 positionTransform = mat4();
+
+    // Radius of rounded corners, if greater than 0. Otherwise, this layer's
+    // corners are not rounded.
+    // Having corner radius will force GPU composition on the layer and its children, drawing it
+    // with a special shader. The shader will receive the radius and the crop rectangle as input,
+    // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
+    // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
+    // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
+    // in local layer coordinate space, so we have to take the layer transform into account when
+    // walking up the tree.
+    float roundedCornersRadius = 0.0;
+
+    // Rectangle within which corners will be rounded.
+    FloatRect roundedCornersCrop = FloatRect();
+};
+
+// Descriptor of the source pixels for this layer.
+struct PixelSource {
+    // Source buffer
+    Buffer buffer = Buffer();
+
+    // The solid color with which to fill the layer.
+    // This should only be populated if we don't render from an application
+    // buffer.
+    half3 solidColor = half3(0.0f, 0.0f, 0.0f);
+};
+
+// The settings that RenderEngine requires for correctly rendering a Layer.
+struct LayerSettings {
+    // Geometry information
+    Geometry geometry = Geometry();
+
+    // Source pixels for this layer.
+    PixelSource source = PixelSource();
+
+    // Alpha option to blend with the source pixels
+    half alpha = half(0.0);
+
+    // Color space describing how the source pixels should be interpreted.
+    ui::Dataspace sourceDataspace = ui::Dataspace::UNKNOWN;
+
+    // Additional layer-specific color transform to be applied before the global
+    // transform.
+    mat4 colorTransform = mat4();
+
+    // True if blending will be forced to be disabled.
+    bool disableBlending = false;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/Mesh.h b/libs/renderengine/include/renderengine/Mesh.h
new file mode 100644
index 0000000..7618424
--- /dev/null
+++ b/libs/renderengine/include/renderengine/Mesh.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2013 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 SF_RENDER_ENGINE_MESH_H
+#define SF_RENDER_ENGINE_MESH_H
+
+#include <vector>
+
+#include <stdint.h>
+
+namespace android {
+namespace renderengine {
+
+class Mesh {
+public:
+    enum Primitive {
+        TRIANGLES = 0x0004,      // GL_TRIANGLES
+        TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP
+        TRIANGLE_FAN = 0x0006    // GL_TRIANGLE_FAN
+    };
+
+    Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
+    ~Mesh() = default;
+
+    /*
+     * VertexArray handles the stride automatically.
+     */
+    template <typename TYPE>
+    class VertexArray {
+        friend class Mesh;
+        float* mData;
+        size_t mStride;
+        VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {}
+
+    public:
+        TYPE& operator[](size_t index) { return *reinterpret_cast<TYPE*>(&mData[index * mStride]); }
+        TYPE const& operator[](size_t index) const {
+            return *reinterpret_cast<TYPE const*>(&mData[index * mStride]);
+        }
+    };
+
+    template <typename TYPE>
+    VertexArray<TYPE> getPositionArray() {
+        return VertexArray<TYPE>(getPositions(), mStride);
+    }
+
+    template <typename TYPE>
+    VertexArray<TYPE> getTexCoordArray() {
+        return VertexArray<TYPE>(getTexCoords(), mStride);
+    }
+
+    template <typename TYPE>
+    VertexArray<TYPE> getCropCoordArray() {
+        return VertexArray<TYPE>(getCropCoords(), mStride);
+    }
+
+    Primitive getPrimitive() const;
+
+    // returns a pointer to the vertices positions
+    float const* getPositions() const;
+
+    // returns a pointer to the vertices texture coordinates
+    float const* getTexCoords() const;
+
+    // returns a pointer to the vertices crop coordinates
+    float const* getCropCoords() const;
+
+    // number of vertices in this mesh
+    size_t getVertexCount() const;
+
+    // dimension of vertices
+    size_t getVertexSize() const;
+
+    // dimension of texture coordinates
+    size_t getTexCoordsSize() const;
+
+    // return stride in bytes
+    size_t getByteStride() const;
+
+    // return stride in floats
+    size_t getStride() const;
+
+private:
+    Mesh(const Mesh&);
+    Mesh& operator=(const Mesh&);
+    Mesh const& operator=(const Mesh&) const;
+
+    float* getPositions();
+    float* getTexCoords();
+    float* getCropCoords();
+
+    std::vector<float> mVertices;
+    size_t mVertexCount;
+    size_t mVertexSize;
+    size_t mTexCoordsSize;
+    size_t mStride;
+    Primitive mPrimitive;
+};
+
+} // namespace renderengine
+} // namespace android
+#endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
new file mode 100644
index 0000000..e707004
--- /dev/null
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2013 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 SF_RENDERENGINE_H_
+#define SF_RENDERENGINE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <memory>
+
+#include <android-base/unique_fd.h>
+#include <math/mat4.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/Framebuffer.h>
+#include <renderengine/Image.h>
+#include <renderengine/LayerSettings.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+
+/**
+ * Allows to set RenderEngine backend to GLES (default) or Vulkan (NOT yet supported).
+ */
+#define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
+
+struct ANativeWindowBuffer;
+
+namespace android {
+
+class Rect;
+class Region;
+
+namespace renderengine {
+
+class BindNativeBufferAsFramebuffer;
+class Image;
+class Mesh;
+class Texture;
+
+namespace impl {
+class RenderEngine;
+}
+
+enum class Protection {
+    UNPROTECTED = 1,
+    PROTECTED = 2,
+};
+
+class RenderEngine {
+public:
+    enum FeatureFlag {
+        USE_COLOR_MANAGEMENT = 1 << 0,      // Device manages color
+        USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
+
+        // Create a protected context when if possible
+        ENABLE_PROTECTED_CONTEXT = 1 << 2,
+    };
+
+    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
+                                                      uint32_t imageCacheSize);
+
+    virtual ~RenderEngine() = 0;
+
+    // ----- BEGIN DEPRECATED INTERFACE -----
+    // This interface, while still in use until a suitable replacement is built,
+    // should be considered deprecated, minus some methods which still may be
+    // used to support legacy behavior.
+
+    virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
+    virtual std::unique_ptr<Image> createImage() = 0;
+
+    virtual void primeCache() const = 0;
+
+    // dump the extension strings. always call the base class.
+    virtual void dump(std::string& result) = 0;
+
+    virtual bool useNativeFenceSync() const = 0;
+    virtual bool useWaitSync() const = 0;
+
+    virtual bool isCurrent() const = 0;
+
+    // helpers
+    // flush submits RenderEngine command stream for execution and returns a
+    // native fence fd that is signaled when the execution has completed.  It
+    // returns -1 on errors.
+    virtual base::unique_fd flush() = 0;
+    // finish waits until RenderEngine command stream has been executed.  It
+    // returns false on errors.
+    virtual bool finish() = 0;
+    // waitFence inserts a wait on an external fence fd to RenderEngine
+    // command stream.  It returns false on errors.
+    virtual bool waitFence(base::unique_fd fenceFd) = 0;
+
+    virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
+    virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
+                                     float alpha) = 0;
+    virtual void genTextures(size_t count, uint32_t* names) = 0;
+    virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
+    virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
+    // Legacy public method used by devices that don't support native fence
+    // synchronization in their GPU driver, as this method provides implicit
+    // synchronization for latching buffers.
+    virtual status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+                                               const sp<Fence>& fence) = 0;
+    // Caches Image resources for this buffer, but does not bind the buffer to
+    // a particular texture.
+    virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
+    // Removes internal resources referenced by the bufferId. This method should be
+    // invoked when the caller will no longer hold a reference to a GraphicBuffer
+    // and needs to clean up its resources.
+    virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
+    // When binding a native buffer, it must be done before setViewportAndProjection
+    // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
+    virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
+    virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
+
+    // set-up
+    virtual void checkErrors() const = 0;
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+                                          ui::Transform::orientation_flags rotation) = 0;
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                    const half4& color, float cornerRadius) = 0;
+    virtual void setupLayerTexturing(const Texture& texture) = 0;
+    virtual void setupLayerBlackedOut() = 0;
+    virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
+    // Sets up the crop size for corner radius clipping.
+    //
+    // Having corner radius will force GPU composition on the layer and its children, drawing it
+    // with a special shader. The shader will receive the radius and the crop rectangle as input,
+    // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
+    // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
+    // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
+    // in local layer coordinate space, so we have to take the layer transform into account when
+    // walking up the tree.
+    virtual void setupCornerRadiusCropSize(float width, float height) = 0;
+
+    // Set a color transform matrix that is applied in linear space right before OETF.
+    virtual void setColorTransform(const mat4& /* colorTransform */) = 0;
+    virtual void disableTexturing() = 0;
+    virtual void disableBlending() = 0;
+
+    // HDR and color management support
+    virtual void setSourceY410BT2020(bool enable) = 0;
+    virtual void setSourceDataSpace(ui::Dataspace source) = 0;
+    virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
+    virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
+
+    // drawing
+    virtual void drawMesh(const Mesh& mesh) = 0;
+
+    // queries
+    virtual size_t getMaxTextureSize() const = 0;
+    virtual size_t getMaxViewportDims() const = 0;
+
+    // ----- END DEPRECATED INTERFACE -----
+
+    // ----- BEGIN NEW INTERFACE -----
+
+    virtual bool isProtected() const = 0;
+    virtual bool supportsProtectedContent() const = 0;
+    virtual bool useProtectedContext(bool useProtectedContext) = 0;
+
+    // Renders layers for a particular display via GPU composition. This method
+    // should be called for every display that needs to be rendered via the GPU.
+    // @param display The display-wide settings that should be applied prior to
+    // drawing any layers.
+    // @param layers The layers to draw onto the display, in Z-order.
+    // @param buffer The buffer which will be drawn to. This buffer will be
+    // ready once drawFence fires.
+    // @param useFramebufferCache True if the framebuffer cache should be used.
+    // If an implementation does not cache output framebuffers, then this
+    // parameter does nothing.
+    // @param bufferFence Fence signalling that the buffer is ready to be drawn
+    // to.
+    // @param drawFence A pointer to a fence, which will fire when the buffer
+    // has been drawn to and is ready to be examined. The fence will be
+    // initialized by this method. The caller will be responsible for owning the
+    // fence.
+    // @return An error code indicating whether drawing was successful. For
+    // now, this always returns NO_ERROR.
+    virtual status_t drawLayers(const DisplaySettings& display,
+                                const std::vector<LayerSettings>& layers,
+                                ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+                                base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
+
+protected:
+    // Gets a framebuffer to render to. This framebuffer may or may not be
+    // cached depending on the implementation.
+    //
+    // Note that this method does not transfer ownership, so the caller most not
+    // live longer than RenderEngine.
+    virtual Framebuffer* getFramebufferForDrawing() = 0;
+    friend class BindNativeBufferAsFramebuffer;
+};
+
+class BindNativeBufferAsFramebuffer {
+public:
+    BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer,
+                                  const bool useFramebufferCache)
+          : mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) {
+        mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected(),
+                                                      useFramebufferCache)
+                ? mEngine.bindFrameBuffer(mFramebuffer)
+                : NO_MEMORY;
+    }
+    ~BindNativeBufferAsFramebuffer() {
+        mFramebuffer->setNativeWindowBuffer(nullptr, false, /*arbitrary*/ true);
+        mEngine.unbindFrameBuffer(mFramebuffer);
+    }
+    status_t getStatus() const { return mStatus; }
+
+private:
+    RenderEngine& mEngine;
+    Framebuffer* mFramebuffer;
+    status_t mStatus;
+};
+
+namespace impl {
+
+// impl::RenderEngine contains common implementation that is graphics back-end agnostic.
+class RenderEngine : public renderengine::RenderEngine {
+public:
+    virtual ~RenderEngine() = 0;
+
+    bool useNativeFenceSync() const override;
+    bool useWaitSync() const override;
+
+protected:
+    RenderEngine(uint32_t featureFlags);
+    const uint32_t mFeatureFlags;
+};
+
+} // namespace impl
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_RENDERENGINE_H_ */
diff --git a/libs/renderengine/include/renderengine/Texture.h b/libs/renderengine/include/renderengine/Texture.h
new file mode 100644
index 0000000..c69ace0
--- /dev/null
+++ b/libs/renderengine/include/renderengine/Texture.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2013 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 SF_RENDER_ENGINE_TEXTURE_H
+#define SF_RENDER_ENGINE_TEXTURE_H
+
+#include <stdint.h>
+
+#include <math/mat4.h>
+
+namespace android {
+namespace renderengine {
+
+class Texture {
+public:
+    enum Target { TEXTURE_2D = 0x0DE1, TEXTURE_EXTERNAL = 0x8D65 };
+
+    Texture();
+    Texture(Target textureTarget, uint32_t textureName);
+    ~Texture();
+
+    void init(Target textureTarget, uint32_t textureName);
+
+    void setMatrix(float const* matrix);
+    void setFiltering(bool enabled);
+    void setDimensions(size_t width, size_t height);
+
+    uint32_t getTextureName() const;
+    uint32_t getTextureTarget() const;
+
+    const mat4& getMatrix() const;
+    bool getFiltering() const;
+    size_t getWidth() const;
+    size_t getHeight() const;
+
+private:
+    uint32_t mTextureName;
+    uint32_t mTextureTarget;
+    size_t mWidth;
+    size_t mHeight;
+    bool mFiltering;
+    mat4 mTextureMatrix;
+};
+
+} // namespace renderengine
+} // namespace android
+#endif /* SF_RENDER_ENGINE_TEXTURE_H */
diff --git a/libs/renderengine/include/renderengine/mock/Framebuffer.h b/libs/renderengine/include/renderengine/mock/Framebuffer.h
new file mode 100644
index 0000000..dfb6a4e
--- /dev/null
+++ b/libs/renderengine/include/renderengine/mock/Framebuffer.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <renderengine/Framebuffer.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+class Framebuffer : public renderengine::Framebuffer {
+public:
+    Framebuffer();
+    ~Framebuffer() override;
+
+    MOCK_METHOD3(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool, const bool));
+};
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/mock/Image.h b/libs/renderengine/include/renderengine/mock/Image.h
new file mode 100644
index 0000000..2b0eed1
--- /dev/null
+++ b/libs/renderengine/include/renderengine/mock/Image.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <renderengine/Image.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+class Image : public renderengine::Image {
+public:
+    Image();
+    ~Image() override;
+
+    MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer* buffer, bool isProtected));
+};
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
new file mode 100644
index 0000000..e33bcfd
--- /dev/null
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/LayerSettings.h>
+#include <renderengine/Mesh.h>
+#include <renderengine/RenderEngine.h>
+#include <renderengine/Texture.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+class RenderEngine : public renderengine::RenderEngine {
+public:
+    RenderEngine();
+    ~RenderEngine() override;
+
+    MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>());
+    MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
+    MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*());
+    MOCK_CONST_METHOD0(primeCache, void());
+    MOCK_METHOD1(dump, void(std::string&));
+    MOCK_CONST_METHOD0(useNativeFenceSync, bool());
+    MOCK_CONST_METHOD0(useWaitSync, bool());
+    MOCK_CONST_METHOD0(isCurrent, bool());
+    MOCK_METHOD0(flush, base::unique_fd());
+    MOCK_METHOD0(finish, bool());
+    MOCK_METHOD1(waitFence, bool(base::unique_fd*));
+    bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
+    MOCK_METHOD4(clearWithColor, void(float, float, float, float));
+    MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
+    MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
+    MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
+    MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
+    MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+    MOCK_METHOD3(bindExternalTextureBuffer,
+                 status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
+    MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
+    MOCK_CONST_METHOD0(checkErrors, void());
+    MOCK_METHOD4(setViewportAndProjection,
+                 void(size_t, size_t, Rect, ui::Transform::orientation_flags));
+    MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float));
+    MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
+    MOCK_METHOD0(setupLayerBlackedOut, void());
+    MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
+    MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float));
+    MOCK_METHOD1(setColorTransform, void(const mat4&));
+    MOCK_METHOD1(setSaturationMatrix, void(const mat4&));
+    MOCK_METHOD0(disableTexturing, void());
+    MOCK_METHOD0(disableBlending, void());
+    MOCK_METHOD1(setSourceY410BT2020, void(bool));
+    MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
+    MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
+    MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
+    MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*));
+    MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*));
+    MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&));
+    MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
+    MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
+    MOCK_CONST_METHOD0(isProtected, bool());
+    MOCK_CONST_METHOD0(supportsProtectedContent, bool());
+    MOCK_METHOD1(useProtectedContext, bool(bool));
+    MOCK_METHOD6(drawLayers,
+                 status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
+                          ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
+};
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
new file mode 100644
index 0000000..bd2055f
--- /dev/null
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013 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 SF_RENDER_ENGINE_DESCRIPTION_H_
+#define SF_RENDER_ENGINE_DESCRIPTION_H_
+
+#include <renderengine/Texture.h>
+#include <ui/GraphicTypes.h>
+
+namespace android {
+namespace renderengine {
+
+/*
+ * This is the structure that holds the state of the rendering engine.
+ * This class is used to generate a corresponding GLSL program and set the
+ * appropriate uniform.
+ */
+struct Description {
+    enum class TransferFunction : int {
+        LINEAR,
+        SRGB,
+        ST2084,
+        HLG, // Hybrid Log-Gamma for HDR.
+    };
+
+    static TransferFunction dataSpaceToTransferFunction(ui::Dataspace dataSpace);
+
+    Description() = default;
+    ~Description() = default;
+
+    bool hasInputTransformMatrix() const;
+    bool hasOutputTransformMatrix() const;
+    bool hasColorMatrix() const;
+
+    // whether textures are premultiplied
+    bool isPremultipliedAlpha = false;
+    // whether this layer is marked as opaque
+    bool isOpaque = true;
+
+    // corner radius of the layer
+    float cornerRadius = 0;
+
+    // Size of the rounded rectangle we are cropping to
+    half2 cropSize;
+
+    // Texture this layer uses
+    Texture texture;
+    bool textureEnabled = false;
+
+    // color used when texturing is disabled or when setting alpha.
+    half4 color;
+
+    // true if the sampled pixel values are in Y410/BT2020 rather than RGBA
+    bool isY410BT2020 = false;
+
+    // transfer functions for the input/output
+    TransferFunction inputTransferFunction = TransferFunction::LINEAR;
+    TransferFunction outputTransferFunction = TransferFunction::LINEAR;
+
+    float displayMaxLuminance;
+
+    // projection matrix
+    mat4 projectionMatrix;
+
+    // The color matrix will be applied in linear space right before OETF.
+    mat4 colorMatrix;
+    mat4 inputTransformMatrix;
+    mat4 outputTransformMatrix;
+};
+
+} // namespace renderengine
+} // namespace android
+
+#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */
diff --git a/libs/renderengine/mock/Framebuffer.cpp b/libs/renderengine/mock/Framebuffer.cpp
new file mode 100644
index 0000000..fbdcaab
--- /dev/null
+++ b/libs/renderengine/mock/Framebuffer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <renderengine/mock/Framebuffer.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Framebuffer::Framebuffer() = default;
+Framebuffer::~Framebuffer() = default;
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/mock/Image.cpp b/libs/renderengine/mock/Image.cpp
new file mode 100644
index 0000000..57f4346
--- /dev/null
+++ b/libs/renderengine/mock/Image.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <renderengine/mock/Image.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Image::Image() = default;
+Image::~Image() = default;
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/mock/RenderEngine.cpp b/libs/renderengine/mock/RenderEngine.cpp
new file mode 100644
index 0000000..261636d
--- /dev/null
+++ b/libs/renderengine/mock/RenderEngine.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <renderengine/mock/RenderEngine.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+RenderEngine::RenderEngine() = default;
+RenderEngine::~RenderEngine() = default;
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
new file mode 100644
index 0000000..9b483ef
--- /dev/null
+++ b/libs/renderengine/tests/Android.bp
@@ -0,0 +1,38 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "librenderengine_test",
+    defaults: ["surfaceflinger_defaults"],
+    test_suites: ["device-tests"],
+    srcs: [
+        "RenderEngineTest.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+        "librenderengine",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libgui",
+        "liblog",
+        "libnativewindow",
+        "libsync",
+        "libui",
+        "libutils",
+    ],
+}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
new file mode 100644
index 0000000..7acaecf
--- /dev/null
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -0,0 +1,1040 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <ui/PixelFormat.h>
+#include "../gl/GLESRenderEngine.h"
+
+constexpr int DEFAULT_DISPLAY_WIDTH = 128;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 256;
+constexpr int DEFAULT_DISPLAY_OFFSET = 64;
+
+namespace android {
+
+struct RenderEngineTest : public ::testing::Test {
+    static void SetUpTestSuite() {
+        sRE = renderengine::gl::GLESRenderEngine::create(static_cast<int32_t>(
+                                                                 ui::PixelFormat::RGBA_8888),
+                                                         0, 1);
+    }
+
+    static void TearDownTestSuite() {
+        // The ordering here is important - sCurrentBuffer must live longer
+        // than RenderEngine to avoid a null reference on tear-down.
+        sRE = nullptr;
+        sCurrentBuffer = nullptr;
+    }
+
+    static sp<GraphicBuffer> allocateDefaultBuffer() {
+        return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                 HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                         GRALLOC_USAGE_HW_RENDER,
+                                 "output");
+    }
+
+    // Allocates a 1x1 buffer to fill with a solid color
+    static sp<GraphicBuffer> allocateSourceBuffer(uint32_t width, uint32_t height) {
+        return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                         GRALLOC_USAGE_HW_TEXTURE,
+                                 "input");
+    }
+
+    RenderEngineTest() { mBuffer = allocateDefaultBuffer(); }
+
+    ~RenderEngineTest() {
+        for (uint32_t texName : mTexNames) {
+            sRE->deleteTextures(1, &texName);
+        }
+    }
+
+    void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
+                           uint8_t tolerance = 0) {
+        uint8_t* pixels;
+        mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                      reinterpret_cast<void**>(&pixels));
+
+        auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
+            uint8_t tmp = a >= b ? a - b : b - a;
+            return tmp <= tolerance;
+        };
+        int32_t maxFails = 10;
+        int32_t fails = 0;
+        for (int32_t j = 0; j < region.getHeight(); j++) {
+            const uint8_t* src =
+                    pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4;
+            for (int32_t i = 0; i < region.getWidth(); i++) {
+                const uint8_t expected[4] = {r, g, b, a};
+                bool equal = std::equal(src, src + 4, expected, colorCompare);
+                EXPECT_TRUE(equal)
+                        << "pixel @ (" << region.left + i << ", " << region.top + j << "): "
+                        << "expected (" << static_cast<uint32_t>(r) << ", "
+                        << static_cast<uint32_t>(g) << ", " << static_cast<uint32_t>(b) << ", "
+                        << static_cast<uint32_t>(a) << "), "
+                        << "got (" << static_cast<uint32_t>(src[0]) << ", "
+                        << static_cast<uint32_t>(src[1]) << ", " << static_cast<uint32_t>(src[2])
+                        << ", " << static_cast<uint32_t>(src[3]) << ")";
+                src += 4;
+                if (!equal && ++fails >= maxFails) {
+                    break;
+                }
+            }
+            if (fails >= maxFails) {
+                break;
+            }
+        }
+        mBuffer->unlock();
+    }
+
+    static Rect fullscreenRect() { return Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); }
+
+    static Rect offsetRect() {
+        return Rect(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_WIDTH,
+                    DEFAULT_DISPLAY_HEIGHT);
+    }
+
+    static Rect offsetRectAtZero() {
+        return Rect(DEFAULT_DISPLAY_WIDTH - DEFAULT_DISPLAY_OFFSET,
+                    DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET);
+    }
+
+    void invokeDraw(renderengine::DisplaySettings settings,
+                    std::vector<renderengine::LayerSettings> layers, sp<GraphicBuffer> buffer) {
+        base::unique_fd fence;
+        status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
+                                          base::unique_fd(), &fence);
+        sCurrentBuffer = buffer;
+
+        int fd = fence.release();
+        if (fd >= 0) {
+            sync_wait(fd, -1);
+            close(fd);
+        }
+
+        ASSERT_EQ(NO_ERROR, status);
+        if (layers.size() > 0) {
+            ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
+        }
+    }
+
+    void drawEmptyLayers() {
+        renderengine::DisplaySettings settings;
+        std::vector<renderengine::LayerSettings> layers;
+        // Meaningless buffer since we don't do any drawing
+        sp<GraphicBuffer> buffer = new GraphicBuffer();
+        invokeDraw(settings, layers, buffer);
+    }
+
+    template <typename SourceVariant>
+    void fillBuffer(half r, half g, half b, half a);
+
+    template <typename SourceVariant>
+    void fillRedBuffer();
+
+    template <typename SourceVariant>
+    void fillGreenBuffer();
+
+    template <typename SourceVariant>
+    void fillBlueBuffer();
+
+    template <typename SourceVariant>
+    void fillRedTransparentBuffer();
+
+    template <typename SourceVariant>
+    void fillRedOffsetBuffer();
+
+    template <typename SourceVariant>
+    void fillBufferPhysicalOffset();
+
+    template <typename SourceVariant>
+    void fillBufferCheckers(mat4 transform);
+
+    template <typename SourceVariant>
+    void fillBufferCheckersRotate0();
+
+    template <typename SourceVariant>
+    void fillBufferCheckersRotate90();
+
+    template <typename SourceVariant>
+    void fillBufferCheckersRotate180();
+
+    template <typename SourceVariant>
+    void fillBufferCheckersRotate270();
+
+    template <typename SourceVariant>
+    void fillBufferWithLayerTransform();
+
+    template <typename SourceVariant>
+    void fillBufferLayerTransform();
+
+    template <typename SourceVariant>
+    void fillBufferWithColorTransform();
+
+    template <typename SourceVariant>
+    void fillBufferColorTransform();
+
+    template <typename SourceVariant>
+    void fillRedBufferWithRoundedCorners();
+
+    template <typename SourceVariant>
+    void fillBufferWithRoundedCorners();
+
+    template <typename SourceVariant>
+    void overlayCorners();
+
+    void fillRedBufferTextureTransform();
+
+    void fillBufferTextureTransform();
+
+    void fillRedBufferWithPremultiplyAlpha();
+
+    void fillBufferWithPremultiplyAlpha();
+
+    void fillRedBufferWithoutPremultiplyAlpha();
+
+    void fillBufferWithoutPremultiplyAlpha();
+
+    void fillGreenColorBufferThenClearRegion();
+
+    void clearLeftRegion();
+
+    void clearRegion();
+
+    // Keep around the same renderengine object to save on initialization time.
+    // For now, exercise the GL backend directly so that some caching specifics
+    // can be tested without changing the interface.
+    static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRE;
+    // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
+    // be freed *after* RenderEngine is destroyed, so that the EGL image is
+    // destroyed first.
+    static sp<GraphicBuffer> sCurrentBuffer;
+
+    sp<GraphicBuffer> mBuffer;
+
+    std::vector<uint32_t> mTexNames;
+};
+
+std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRE = nullptr;
+sp<GraphicBuffer> RenderEngineTest::sCurrentBuffer = nullptr;
+
+struct ColorSourceVariant {
+    static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
+                          RenderEngineTest* /*fixture*/) {
+        layer.source.solidColor = half3(r, g, b);
+    }
+};
+
+struct RelaxOpaqueBufferVariant {
+    static void setOpaqueBit(renderengine::LayerSettings& layer) {
+        layer.source.buffer.isOpaque = false;
+    }
+
+    static uint8_t getAlphaChannel() { return 255; }
+};
+
+struct ForceOpaqueBufferVariant {
+    static void setOpaqueBit(renderengine::LayerSettings& layer) {
+        layer.source.buffer.isOpaque = true;
+    }
+
+    static uint8_t getAlphaChannel() {
+        // The isOpaque bit will override the alpha channel, so this should be
+        // arbitrary.
+        return 10;
+    }
+};
+
+template <typename OpaquenessVariant>
+struct BufferSourceVariant {
+    static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
+                          RenderEngineTest* fixture) {
+        sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
+        uint32_t texName;
+        fixture->sRE->genTextures(1, &texName);
+        fixture->mTexNames.push_back(texName);
+
+        uint8_t* pixels;
+        buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                  reinterpret_cast<void**>(&pixels));
+
+        for (int32_t j = 0; j < buf->getHeight(); j++) {
+            uint8_t* iter = pixels + (buf->getStride() * j) * 4;
+            for (int32_t i = 0; i < buf->getWidth(); i++) {
+                iter[0] = uint8_t(r * 255);
+                iter[1] = uint8_t(g * 255);
+                iter[2] = uint8_t(b * 255);
+                iter[3] = OpaquenessVariant::getAlphaChannel();
+                iter += 4;
+            }
+        }
+
+        buf->unlock();
+
+        layer.source.buffer.buffer = buf;
+        layer.source.buffer.textureName = texName;
+        OpaquenessVariant::setOpaqueBit(layer);
+    }
+};
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBuffer(half r, half g, half b, half a) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    SourceVariant::fillColor(layer, r, g, b, this);
+    layer.alpha = a;
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedBuffer() {
+    fillBuffer<SourceVariant>(1.0f, 0.0f, 0.0f, 1.0f);
+    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillGreenBuffer() {
+    fillBuffer<SourceVariant>(0.0f, 1.0f, 0.0f, 1.0f);
+    expectBufferColor(fullscreenRect(), 0, 255, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBlueBuffer() {
+    fillBuffer<SourceVariant>(0.0f, 0.0f, 1.0f, 1.0f);
+    expectBufferColor(fullscreenRect(), 0, 0, 255, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedTransparentBuffer() {
+    fillBuffer<SourceVariant>(1.0f, 0.0f, 0.0f, .2f);
+    expectBufferColor(fullscreenRect(), 51, 0, 0, 51);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedOffsetBuffer() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = offsetRect();
+    settings.clip = offsetRectAtZero();
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
+    SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0f;
+
+    layers.push_back(layer);
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferPhysicalOffset() {
+    fillRedOffsetBuffer<SourceVariant>();
+
+    expectBufferColor(Rect(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_WIDTH,
+                           DEFAULT_DISPLAY_HEIGHT),
+                      255, 0, 0, 255);
+    Rect offsetRegionLeft(DEFAULT_DISPLAY_OFFSET, DEFAULT_DISPLAY_HEIGHT);
+    Rect offsetRegionTop(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_OFFSET);
+
+    expectBufferColor(offsetRegionLeft, 0, 0, 0, 0);
+    expectBufferColor(offsetRegionTop, 0, 0, 0, 0);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckers(mat4 transform) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    // Here logical space is 2x2
+    settings.clip = Rect(2, 2);
+    settings.globalTransform = transform;
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layerOne;
+    Rect rectOne(0, 0, 1, 1);
+    layerOne.geometry.boundaries = rectOne.toFloatRect();
+    SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
+    layerOne.alpha = 1.0f;
+
+    renderengine::LayerSettings layerTwo;
+    Rect rectTwo(0, 1, 1, 2);
+    layerTwo.geometry.boundaries = rectTwo.toFloatRect();
+    SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
+    layerTwo.alpha = 1.0f;
+
+    renderengine::LayerSettings layerThree;
+    Rect rectThree(1, 0, 2, 1);
+    layerThree.geometry.boundaries = rectThree.toFloatRect();
+    SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
+    layerThree.alpha = 1.0f;
+
+    layers.push_back(layerOne);
+    layers.push_back(layerTwo);
+    layers.push_back(layerThree);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate0() {
+    fillBufferCheckers<SourceVariant>(mat4());
+    expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0,
+                      255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+                           DEFAULT_DISPLAY_HEIGHT / 2),
+                      0, 0, 255, 255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 0, 0);
+    expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+                           DEFAULT_DISPLAY_HEIGHT),
+                      0, 255, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate90() {
+    mat4 matrix = mat4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1);
+    fillBufferCheckers<SourceVariant>(matrix);
+    expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 255, 0,
+                      255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+                           DEFAULT_DISPLAY_HEIGHT / 2),
+                      255, 0, 0, 255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 255, 255);
+    expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+                           DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 0, 0);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate180() {
+    mat4 matrix = mat4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 2, 2, 0, 1);
+    fillBufferCheckers<SourceVariant>(matrix);
+    expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0,
+                      0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+                           DEFAULT_DISPLAY_HEIGHT / 2),
+                      0, 255, 0, 255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      255, 0, 0, 255);
+    expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+                           DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 255, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferCheckersRotate270() {
+    mat4 matrix = mat4(0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1);
+    fillBufferCheckers<SourceVariant>(matrix);
+    expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 255,
+                      255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+                           DEFAULT_DISPLAY_HEIGHT / 2),
+                      0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 255, 0, 255);
+    expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT / 2, DEFAULT_DISPLAY_WIDTH / 2,
+                           DEFAULT_DISPLAY_HEIGHT),
+                      255, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithLayerTransform() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    // Here logical space is 2x2
+    settings.clip = Rect(2, 2);
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+    // Translate one pixel diagonally
+    layer.geometry.positionTransform = mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1);
+    SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
+    layer.alpha = 1.0f;
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferLayerTransform() {
+    fillBufferWithLayerTransform<SourceVariant>();
+    expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0, 0);
+    expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      255, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithColorTransform() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = Rect(1, 1);
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+    SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+    layer.alpha = 1.0f;
+
+    // construct a fake color matrix
+    // annihilate green and blue channels
+    settings.colorTransform = mat4::scale(vec4(1, 0, 0, 1));
+    // set red channel to red + green
+    layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+
+    layer.alpha = 1.0f;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransform() {
+    fillBufferWithColorTransform<SourceVariant>();
+    expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillRedBufferWithRoundedCorners() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    layer.geometry.roundedCornersRadius = 5.0f;
+    layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
+    SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0f;
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithRoundedCorners() {
+    fillRedBufferWithRoundedCorners<SourceVariant>();
+    // Corners should be ignored...
+    expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, 0, DEFAULT_DISPLAY_WIDTH, 1), 0, 0, 0, 0);
+    expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT - 1, 1, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 0, 0);
+    // ...And the non-rounded portion should be red.
+    // Other pixels may be anti-aliased, so let's not check those.
+    expectBufferColor(Rect(5, 5, DEFAULT_DISPLAY_WIDTH - 5, DEFAULT_DISPLAY_HEIGHT - 5), 255, 0, 0,
+                      255);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::overlayCorners() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layersFirst;
+
+    renderengine::LayerSettings layerOne;
+    layerOne.geometry.boundaries =
+            FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0);
+    SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
+    layerOne.alpha = 0.2;
+
+    layersFirst.push_back(layerOne);
+    invokeDraw(settings, layersFirst, mBuffer);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 0, 0);
+
+    std::vector<renderengine::LayerSettings> layersSecond;
+    renderengine::LayerSettings layerTwo;
+    layerTwo.geometry.boundaries =
+            FloatRect(DEFAULT_DISPLAY_WIDTH / 3.0, DEFAULT_DISPLAY_HEIGHT / 3.0,
+                      DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+    SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
+    layerTwo.alpha = 1.0f;
+
+    layersSecond.push_back(layerTwo);
+    invokeDraw(settings, layersSecond, mBuffer);
+
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 255, 0, 255);
+}
+
+void RenderEngineTest::fillRedBufferTextureTransform() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = Rect(1, 1);
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    // Here will allocate a checker board texture, but transform texture
+    // coordinates so that only the upper left is applied.
+    sp<GraphicBuffer> buf = allocateSourceBuffer(2, 2);
+    uint32_t texName;
+    RenderEngineTest::sRE->genTextures(1, &texName);
+    this->mTexNames.push_back(texName);
+
+    uint8_t* pixels;
+    buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+              reinterpret_cast<void**>(&pixels));
+    // Red top left, Green top right, Blue bottom left, Black bottom right
+    pixels[0] = 255;
+    pixels[1] = 0;
+    pixels[2] = 0;
+    pixels[3] = 255;
+    pixels[4] = 0;
+    pixels[5] = 255;
+    pixels[6] = 0;
+    pixels[7] = 255;
+    pixels[8] = 0;
+    pixels[9] = 0;
+    pixels[10] = 255;
+    pixels[11] = 255;
+    buf->unlock();
+
+    layer.source.buffer.buffer = buf;
+    layer.source.buffer.textureName = texName;
+    // Transform coordinates to only be inside the red quadrant.
+    layer.source.buffer.textureTransform = mat4::scale(vec4(0.2, 0.2, 1, 1));
+    layer.alpha = 1.0f;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferTextureTransform() {
+    fillRedBufferTextureTransform();
+    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
+void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    // Here logical space is 1x1
+    settings.clip = Rect(1, 1);
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+    uint32_t texName;
+    RenderEngineTest::sRE->genTextures(1, &texName);
+    this->mTexNames.push_back(texName);
+
+    uint8_t* pixels;
+    buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+              reinterpret_cast<void**>(&pixels));
+    pixels[0] = 255;
+    pixels[1] = 0;
+    pixels[2] = 0;
+    pixels[3] = 255;
+    buf->unlock();
+
+    layer.source.buffer.buffer = buf;
+    layer.source.buffer.textureName = texName;
+    layer.source.buffer.usePremultipliedAlpha = true;
+    layer.alpha = 0.5f;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferWithPremultiplyAlpha() {
+    fillRedBufferWithPremultiplyAlpha();
+    expectBufferColor(fullscreenRect(), 128, 0, 0, 128);
+}
+
+void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    // Here logical space is 1x1
+    settings.clip = Rect(1, 1);
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+    uint32_t texName;
+    RenderEngineTest::sRE->genTextures(1, &texName);
+    this->mTexNames.push_back(texName);
+
+    uint8_t* pixels;
+    buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+              reinterpret_cast<void**>(&pixels));
+    pixels[0] = 255;
+    pixels[1] = 0;
+    pixels[2] = 0;
+    pixels[3] = 255;
+    buf->unlock();
+
+    layer.source.buffer.buffer = buf;
+    layer.source.buffer.textureName = texName;
+    layer.source.buffer.usePremultipliedAlpha = false;
+    layer.alpha = 0.5f;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() {
+    fillRedBufferWithoutPremultiplyAlpha();
+    expectBufferColor(fullscreenRect(), 128, 0, 0, 64, 1);
+}
+
+void RenderEngineTest::clearLeftRegion() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    // Here logical space is 4x4
+    settings.clip = Rect(4, 4);
+    settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
+    settings.clearRegion = Region(Rect(1, 1));
+    std::vector<renderengine::LayerSettings> layers;
+    // dummy layer, without bounds should not render anything
+    renderengine::LayerSettings layer;
+    layers.push_back(layer);
+    invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::clearRegion() {
+    // Reuse mBuffer
+    clearLeftRegion();
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+                           DEFAULT_DISPLAY_HEIGHT),
+                      0, 0, 0, 0);
+}
+
+TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
+    drawEmptyLayers();
+}
+
+TEST_F(RenderEngineTest, drawLayers_nullOutputBuffer) {
+    renderengine::DisplaySettings settings;
+    std::vector<renderengine::LayerSettings> layers;
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layers.push_back(layer);
+    base::unique_fd fence;
+    status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
+
+    ASSERT_EQ(BAD_VALUE, status);
+}
+
+TEST_F(RenderEngineTest, drawLayers_nullOutputFence) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0;
+    layers.push_back(layer);
+
+    status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
+                                      base::unique_fd(), nullptr);
+    sCurrentBuffer = mBuffer;
+    ASSERT_EQ(NO_ERROR, status);
+    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
+TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0;
+    layers.push_back(layer);
+
+    status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
+                                      base::unique_fd(), nullptr);
+    sCurrentBuffer = mBuffer;
+    ASSERT_EQ(NO_ERROR, status);
+    ASSERT_FALSE(sRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+    expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
+    fillRedBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
+    fillGreenBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
+    fillBlueBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
+    fillRedTransparentBuffer<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
+    fillBufferPhysicalOffset<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
+    fillBufferCheckersRotate0<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
+    fillBufferCheckersRotate90<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
+    fillBufferCheckersRotate180<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
+    fillBufferCheckersRotate270<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
+    fillBufferLayerTransform<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
+    fillBufferLayerTransform<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
+    fillBufferWithRoundedCorners<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
+    overlayCorners<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
+    fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
+    fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
+    fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
+    fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
+    fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
+    fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
+    fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
+    fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
+    fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
+    fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
+    fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
+    fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
+    overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
+    fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
+    fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
+    fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
+    fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
+    fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
+    fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
+    fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
+    fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
+    fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
+    fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
+    fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
+    fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
+    overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
+    fillBufferTextureTransform();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
+    fillBufferWithPremultiplyAlpha();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
+    fillBufferWithoutPremultiplyAlpha();
+}
+
+TEST_F(RenderEngineTest, drawLayers_clearRegion) {
+    clearRegion();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<renderengine::LayerSettings> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+
+    layers.push_back(layer);
+    invokeDraw(settings, layers, mBuffer);
+    uint64_t bufferId = layer.source.buffer.buffer->getId();
+    EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+    sRE->unbindExternalTextureBuffer(bufferId);
+    EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+}
+
+TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
+    status_t result = sRE->bindExternalTextureBuffer(0, nullptr, nullptr);
+    ASSERT_EQ(BAD_VALUE, result);
+}
+
+TEST_F(RenderEngineTest, drawLayers_bindExternalBufferCachesImages) {
+    sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+    uint32_t texName;
+    sRE->genTextures(1, &texName);
+    mTexNames.push_back(texName);
+
+    sRE->bindExternalTextureBuffer(texName, buf, nullptr);
+    uint64_t bufferId = buf->getId();
+    EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+    sRE->unbindExternalTextureBuffer(bufferId);
+    EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+}
+
+TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
+    status_t result = sRE->cacheExternalTextureBuffer(nullptr);
+    ASSERT_EQ(BAD_VALUE, result);
+}
+
+TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
+    sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+    uint64_t bufferId = buf->getId();
+    sRE->cacheExternalTextureBuffer(buf);
+    EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+    sRE->unbindExternalTextureBuffer(bufferId);
+    EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+}
+
+} // namespace android
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
index d4393d6..81099e8 100644
--- a/libs/sensor/OWNERS
+++ b/libs/sensor/OWNERS
@@ -1,2 +1,3 @@
 arthuri@google.com
 bduddie@google.com
+bstack@google.com
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 2383516..abc9103 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -22,6 +22,13 @@
 #include <binder/IPermissionController.h>
 #include <binder/IServiceManager.h>
 
+/*
+ * The permission to use for activity recognition sensors (like step counter).
+ * See sensor types for more details on what sensors should require this
+ * permission.
+ */
+#define SENSOR_PERMISSION_ACTIVITY_RECOGNITION "android.permission.ACTIVITY_RECOGNITION"
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -116,7 +123,7 @@
         mStringType = SENSOR_STRING_TYPE_HEART_RATE;
         mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
         AppOpsManager appOps;
-        mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
+        mRequiredAppOp = appOps.permissionToOpCode(String16(mRequiredPermission));
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
         } break;
     case SENSOR_TYPE_LIGHT:
@@ -165,14 +172,22 @@
             mFlags |= SENSOR_FLAG_WAKE_UP;
         }
         break;
-    case SENSOR_TYPE_STEP_COUNTER:
+    case SENSOR_TYPE_STEP_COUNTER: {
         mStringType = SENSOR_STRING_TYPE_STEP_COUNTER;
+        mRequiredPermission = SENSOR_PERMISSION_ACTIVITY_RECOGNITION;
+        AppOpsManager appOps;
+        mRequiredAppOp =
+                appOps.permissionToOpCode(String16(mRequiredPermission));
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
-    case SENSOR_TYPE_STEP_DETECTOR:
+        } break;
+    case SENSOR_TYPE_STEP_DETECTOR: {
         mStringType = SENSOR_STRING_TYPE_STEP_DETECTOR;
+        mRequiredPermission = SENSOR_PERMISSION_ACTIVITY_RECOGNITION;
+        AppOpsManager appOps;
+        mRequiredAppOp =
+                appOps.permissionToOpCode(String16(mRequiredPermission));
         mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
-        break;
+        } break;
     case SENSOR_TYPE_TEMPERATURE:
         mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
@@ -318,7 +333,7 @@
         // If the sensor is protected by a permission we need to know if it is
         // a runtime one to determine whether we can use the permission cache.
         sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
-        if (binder != 0) {
+        if (binder != nullptr) {
             sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
             mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
                     String16(mRequiredPermission));
diff --git a/libs/sensor/SensorEventQueue.cpp b/libs/sensor/SensorEventQueue.cpp
index 6f68fb5..4438d45 100644
--- a/libs/sensor/SensorEventQueue.cpp
+++ b/libs/sensor/SensorEventQueue.cpp
@@ -29,6 +29,7 @@
 #include <sensor/ISensorEventConnection.h>
 
 #include <android/sensor.h>
+#include <hardware/sensors-base.h>
 
 using std::min;
 
@@ -37,7 +38,7 @@
 // ----------------------------------------------------------------------------
 
 SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection)
-    : mSensorEventConnection(connection), mRecBuffer(NULL), mAvailable(0), mConsumed(0),
+    : mSensorEventConnection(connection), mRecBuffer(nullptr), mAvailable(0), mConsumed(0),
       mNumAcksToSend(0) {
     mRecBuffer = new ASensorEvent[MAX_RECEIVE_BUFFER_EVENT_COUNT];
 }
@@ -82,9 +83,9 @@
 sp<Looper> SensorEventQueue::getLooper() const
 {
     Mutex::Autolock _l(mLock);
-    if (mLooper == 0) {
+    if (mLooper == nullptr) {
         mLooper = new Looper(true);
-        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
+        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, nullptr, nullptr);
     }
     return mLooper;
 }
@@ -97,7 +98,7 @@
     int events;
     int32_t result;
     do {
-        result = looper->pollOnce(-1, NULL, &events, NULL);
+        result = looper->pollOnce(-1, nullptr, &events, nullptr);
         if (result == ALOOPER_POLL_ERROR) {
             ALOGE("SensorEventQueue::waitForEvent error (errno=%d)", errno);
             result = -EPIPE; // unknown error, so we make up one
@@ -188,6 +189,52 @@
     return;
 }
 
+ssize_t SensorEventQueue::filterEvents(ASensorEvent* events, size_t count) const {
+    // Check if this Sensor Event Queue is registered to receive each type of event. If it is not,
+    // then do not copy the event into the final buffer. Minimize the number of copy operations by
+    // finding consecutive sequences of events that the Sensor Event Queue should receive and only
+    // copying the events once an unregistered event type is reached.
+    bool intervalStartLocSet = false;
+    size_t intervalStartLoc = 0;
+    size_t eventsInInterval = 0;
+    ssize_t eventsCopied = 0;
+
+    for (size_t i = 0; i < count; i++) {
+        bool includeEvent =
+                (events[i].type != SENSOR_TYPE_ADDITIONAL_INFO || requestAdditionalInfo);
+
+        if (includeEvent) {
+            // Do not copy events yet since there may be more consecutive events that should be
+            // copied together. Track the start location and number of events in the current
+            // sequence.
+            if (!intervalStartLocSet) {
+                intervalStartLoc = i;
+                intervalStartLocSet = true;
+                eventsInInterval = 0;
+            }
+            eventsInInterval++;
+        }
+
+        // Shift the events from the already processed interval once an event that should not be
+        // included is reached or if this is the final event to be processed.
+        if (!includeEvent || (i + 1 == count)) {
+            // Only shift the events if the interval did not start with the first event. If the
+            // interval started with the first event, the events are already in their correct
+            // location.
+            if (intervalStartLoc > 0) {
+                memmove(&events[eventsCopied], &events[intervalStartLoc],
+                        eventsInInterval * sizeof(ASensorEvent));
+            }
+            eventsCopied += eventsInInterval;
+
+            // Reset the interval information
+            eventsInInterval = 0;
+            intervalStartLocSet = false;
+        }
+    }
+    return eventsCopied;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index c97e4da..96d5eb9 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -62,7 +62,7 @@
         // to the wrong package and stats based on app ops may be slightly off.
         if (opPackageName.size() <= 0) {
             sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
-            if (binder != 0) {
+            if (binder != nullptr) {
                 const uid_t uid = IPCThreadState::self()->getCallingUid();
                 Vector<String16> packages;
                 interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
@@ -93,7 +93,7 @@
 }
 
 SensorManager::SensorManager(const String16& opPackageName)
-    : mSensorList(0), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
+    : mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
     Mutex::Autolock _l(mLock);
     assertStateLocked();
 }
@@ -128,13 +128,13 @@
     Mutex::Autolock _l(mLock);
     mSensorServer.clear();
     free(mSensorList);
-    mSensorList = NULL;
+    mSensorList = nullptr;
     mSensors.clear();
 }
 
 status_t SensorManager::assertStateLocked() {
     bool initSensorManager = false;
-    if (mSensorServer == NULL) {
+    if (mSensorServer == nullptr) {
         initSensorManager = true;
     } else {
         // Ping binder to check if sensorservice is alive.
@@ -164,7 +164,7 @@
         size_t count = mSensors.size();
         mSensorList =
                 static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
-        LOG_ALWAYS_FATAL_IF(mSensorList == NULL, "mSensorList NULL");
+        LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
 
         for (size_t i=0 ; i<count ; i++) {
             mSensorList[i] = mSensors.array() + i;
@@ -222,7 +222,7 @@
             }
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
@@ -232,10 +232,10 @@
     while (assertStateLocked() == NO_ERROR) {
         sp<ISensorEventConnection> connection =
                 mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
-        if (connection == NULL) {
+        if (connection == nullptr) {
             // SensorService just died or the app doesn't have required permissions.
             ALOGE("createEventQueue: connection is NULL.");
-            return NULL;
+            return nullptr;
         }
         queue = new SensorEventQueue(connection);
         break;
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 6926f7f..324d443 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -57,15 +57,15 @@
             uint8_t b[16];
             int64_t i64[2];
         };
-        uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
+        explicit uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
         uuid_t() : b{0} {}
     };
 
     Sensor(const Sensor&) = default;
     Sensor& operator=(const Sensor&) = default;
 
-    Sensor(const char * name = "");
-    Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
+    explicit Sensor(const char * name = "");
+    explicit Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
     Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
     ~Sensor();
 
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index baed2ee..8c3fde0 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -34,6 +34,7 @@
 // Concrete types for the NDK
 struct ASensorEventQueue {
     ALooper* looper;
+    bool requestAdditionalInfo;
 };
 
 // ----------------------------------------------------------------------------
@@ -64,7 +65,7 @@
     // Default sensor sample period
     static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
 
-    SensorEventQueue(const sp<ISensorEventConnection>& connection);
+    explicit SensorEventQueue(const sp<ISensorEventConnection>& connection);
     virtual ~SensorEventQueue();
     virtual void onFirstRef();
 
@@ -92,6 +93,13 @@
     void sendAck(const ASensorEvent* events, int count);
 
     status_t injectSensorEvent(const ASensorEvent& event);
+
+    // Filters the given sensor events in place and returns the new number of events.
+    //
+    // The filtering is controlled by ASensorEventQueue.requestAdditionalInfo, and if this value is
+    // false, then all SENSOR_TYPE_ADDITIONAL_INFO sensor events will be removed.
+    ssize_t filterEvents(ASensorEvent* events, size_t count) const;
+
 private:
     sp<Looper> getLooper() const;
     sp<ISensorEventConnection> mSensorEventConnection;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 23f7a91..f09c9c6 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -71,7 +71,7 @@
     void sensorManagerDied();
     static status_t waitForSensorService(sp<ISensorServer> *server);
 
-    SensorManager(const String16& opPackageName);
+    explicit SensorManager(const String16& opPackageName);
     status_t assertStateLocked();
 
 private:
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index 9fd84bc..c9a7668 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -21,6 +21,7 @@
 
     srcs: [
         "Sensor_test.cpp",
+        "SensorEventQueue_test.cpp",
     ],
 
     shared_libs: [
diff --git a/libs/sensor/tests/SensorEventQueue_test.cpp b/libs/sensor/tests/SensorEventQueue_test.cpp
new file mode 100644
index 0000000..1eb5883
--- /dev/null
+++ b/libs/sensor/tests/SensorEventQueue_test.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+#include <utils/Errors.h>
+
+#include <android/sensor.h>
+#include <hardware/sensors-base.h>
+#include <sensor/SensorManager.h>
+#include <sensor/SensorEventQueue.h>
+
+namespace android {
+
+class SensorEventQueueTest : public ::testing::Test {
+protected:
+    typedef std::vector<int32_t> Events;
+
+    SensorEventQueueTest() {};
+
+    virtual void SetUp() override {
+        SensorManager& manager = SensorManager::getInstanceForPackage(String16("SensorEventQueueTest"));
+        mQueue = manager.createEventQueue();
+    }
+
+    void configureAdditionalInfo(bool enable) {
+        mQueue->requestAdditionalInfo = enable;
+    }
+
+    Events filterEvents(const Events &types) const {
+        // Convert the events into SensorEvent array
+        ASensorEvent* events = new ASensorEvent[types.size()];
+        for (size_t i = 0; i < types.size(); i++) {
+            events[i].type = types[i];
+        }
+
+        // Filter the events
+        ssize_t filteredCount = mQueue->filterEvents(events, types.size());
+
+        // Copy the result into an output vector
+        Events result;
+        for (size_t i = 0; i < filteredCount; i++) {
+            result.push_back(events[i].type);
+        }
+        delete[] events;
+
+        return result;
+    }
+
+    Events getExpectedEvents(const Events &events) const {
+        Events output;
+        for (size_t i = 0; i != events.size(); i++) {
+            // Copy events if the event queue is configured to receive them
+            if (events[i] != SENSOR_TYPE_ADDITIONAL_INFO || mQueue->requestAdditionalInfo) {
+                output.push_back(events[i]);
+            }
+        }
+        return output;
+    }
+
+    void runFilterTest(const Events& events) {
+        Events filtered = filterEvents(events);
+        Events expected = getExpectedEvents(events);
+        EXPECT_EQ(expected.size(), filtered.size());
+        EXPECT_EQ(expected, filtered);
+    }
+
+private:
+    sp<SensorEventQueue> mQueue;
+};
+
+TEST_F(SensorEventQueueTest, FilterZeroEvents) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_ReceiveAdditionalInfo) {
+    configureAdditionalInfo(true /* enable */);
+    runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ACCELEROMETER,
+                   SENSOR_TYPE_GYROSCOPE,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_MAGNETIC_FIELD});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveAll) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveFirst) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ACCELEROMETER,
+                   SENSOR_TYPE_GYROSCOPE,
+                   SENSOR_TYPE_MAGNETIC_FIELD});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveAllButOne) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ACCELEROMETER,
+                   SENSOR_TYPE_ADDITIONAL_INFO});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveLast) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({SENSOR_TYPE_ACCELEROMETER,
+                   SENSOR_TYPE_GYROSCOPE,
+                   SENSOR_TYPE_MAGNETIC_FIELD,
+                   SENSOR_TYPE_ADDITIONAL_INFO});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveConsecutive) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({SENSOR_TYPE_MAGNETIC_FIELD,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ACCELEROMETER});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveInterleaved) {
+    configureAdditionalInfo(false /* enable */);
+    runFilterTest({SENSOR_TYPE_ACCELEROMETER,
+                   SENSOR_TYPE_GYROSCOPE,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_ACCELEROMETER,
+                   SENSOR_TYPE_GYROSCOPE,
+                   SENSOR_TYPE_ADDITIONAL_INFO,
+                   SENSOR_TYPE_MAGNETIC_FIELD});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_ReconfigureAdditionalInfo) {
+    configureAdditionalInfo(false /* enable */);
+    const Events events = {SENSOR_TYPE_ACCELEROMETER,
+                           SENSOR_TYPE_GYROSCOPE,
+                           SENSOR_TYPE_ADDITIONAL_INFO,
+                           SENSOR_TYPE_MAGNETIC_FIELD,
+                           SENSOR_TYPE_ADDITIONAL_INFO};
+    runFilterTest(events);
+
+    // Update setting to request Additional Info
+    configureAdditionalInfo(true /* enable */);
+    runFilterTest(events);
+
+    // Update setting to stop requesting Additional Info
+    configureAdditionalInfo(true /* enable */);
+    runFilterTest(events);
+}
+
+} // namespace android
diff --git a/libs/sensorprivacy/Android.bp b/libs/sensorprivacy/Android.bp
new file mode 100644
index 0000000..e0e3469
--- /dev/null
+++ b/libs/sensorprivacy/Android.bp
@@ -0,0 +1,47 @@
+// Copyright 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libsensorprivacy",
+
+    aidl: {
+        export_aidl_headers: true,
+        local_include_dirs: ["aidl"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wzero-as-null-pointer-constant",
+    ],
+
+    srcs: [
+        "aidl/android/hardware/ISensorPrivacyListener.aidl",
+        "aidl/android/hardware/ISensorPrivacyManager.aidl",
+        "SensorPrivacyManager.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libhardware",
+    ],
+
+    export_include_dirs: ["include"],
+
+    export_shared_lib_headers: ["libbinder"],
+}
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
new file mode 100644
index 0000000..f973cba
--- /dev/null
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <unistd.h>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <sensorprivacy/SensorPrivacyManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+SensorPrivacyManager::SensorPrivacyManager()
+{
+}
+
+sp<hardware::ISensorPrivacyManager> SensorPrivacyManager::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<hardware::ISensorPrivacyManager> service = mService;
+    while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("sensor_privacy"));
+        if (binder == nullptr) {
+            // Wait for the sensor privacy service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for sensor privacy service");
+            } else if ((uptimeMillis() - startTime) > 1000000) {
+                ALOGW("Waiting too long for sensor privacy service, giving up");
+                service = nullptr;
+                break;
+            }
+            usleep(25000);
+        } else {
+            service = interface_cast<hardware::ISensorPrivacyManager>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+void SensorPrivacyManager::addSensorPrivacyListener(
+        const sp<hardware::ISensorPrivacyListener>& listener)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        service->addSensorPrivacyListener(listener);
+    }
+}
+
+void SensorPrivacyManager::removeSensorPrivacyListener(
+        const sp<hardware::ISensorPrivacyListener>& listener)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        service->removeSensorPrivacyListener(listener);
+    }
+}
+
+bool SensorPrivacyManager::isSensorPrivacyEnabled()
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        bool result;
+        service->isSensorPrivacyEnabled(&result);
+        return result;
+    }
+    // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+    return false;
+}
+
+status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        return IInterface::asBinder(service)->linkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t SensorPrivacyManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        return IInterface::asBinder(service)->unlinkToDeath(recipient);
+    }
+    return INVALID_OPERATION;
+}
+
+}; // namespace android
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
new file mode 100644
index 0000000..58177d8
--- /dev/null
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * @hide
+ */
+oneway interface ISensorPrivacyListener {
+    void onSensorPrivacyChanged(boolean enabled);
+}
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
new file mode 100644
index 0000000..4c2d5db
--- /dev/null
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+import android.hardware.ISensorPrivacyListener;
+
+/** @hide */
+interface ISensorPrivacyManager {
+    void addSensorPrivacyListener(in ISensorPrivacyListener listener);
+
+    void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
+
+    boolean isSensorPrivacyEnabled();
+
+    void setSensorPrivacy(boolean enable);
+}
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
new file mode 100644
index 0000000..2546a68
--- /dev/null
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_PRIVACY_MANAGER_H
+#define ANDROID_SENSOR_PRIVACY_MANAGER_H
+
+#include "android/hardware/ISensorPrivacyListener.h"
+#include "android/hardware/ISensorPrivacyManager.h"
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class SensorPrivacyManager
+{
+public:
+    SensorPrivacyManager();
+
+    void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
+    void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
+    bool isSensorPrivacyEnabled();
+
+    status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+    status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
+private:
+    Mutex mLock;
+    sp<hardware::ISensorPrivacyManager> mService;
+    sp<hardware::ISensorPrivacyManager> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SENSOR_PRIVACY_MANAGER_H
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index ff9d19e..0407d88 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -18,6 +18,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
 
     clang: true,
     cflags: [
@@ -44,6 +45,8 @@
 
         // Don't warn about struct padding
         "-Wno-padded",
+
+        "-Wno-switch-enum",
     ],
 
     sanitize: {
@@ -52,18 +55,26 @@
 
     srcs: [
         "ColorSpace.cpp",
+        "BufferHubBuffer.cpp",
+        "BufferHubEventFd.cpp",
+        "BufferHubMetadata.cpp",
         "DebugUtils.cpp",
         "Fence.cpp",
         "FenceTime.cpp",
         "FrameStats.cpp",
+        "Gralloc.cpp",
         "Gralloc2.cpp",
+        "Gralloc3.cpp",
         "GraphicBuffer.cpp",
         "GraphicBufferAllocator.cpp",
         "GraphicBufferMapper.cpp",
         "HdrCapabilities.cpp",
         "PixelFormat.cpp",
+        "PublicFormat.cpp",
         "Rect.cpp",
         "Region.cpp",
+        "Size.cpp",
+        "Transform.cpp",
         "UiConfig.cpp",
     ],
 
@@ -71,13 +82,17 @@
         "frameworks/native/include",
     ],
 
+    // Uncomment the following line to enable VALIDATE_REGIONS traces
+    //defaults: ["libui-validate-regions-defaults"],
+
     shared_libs: [
+        "android.frameworks.bufferhub@1.0",
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
-        "android.hardware.configstore@1.0",
-        "android.hardware.configstore-utils",
+        "android.hardware.graphics.mapper@3.0",
         "libbase",
         "libcutils",
         "libhardware",
@@ -86,12 +101,11 @@
         "libhwbinder",
         "libsync",
         "libutils",
-        "libutilscallstack",
         "liblog",
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
     ],
 
     static_libs: [
@@ -100,9 +114,32 @@
         "libmath",
     ],
 
+    // bufferhub is not used when building libgui for vendors
+    target: {
+        vendor: {
+            cflags: ["-DLIBUI_IN_VNDK"],
+            exclude_srcs: [
+                "BufferHubBuffer.cpp",
+                "BufferHubEventFd.cpp",
+                "BufferHubMetadata.cpp",
+            ],
+            exclude_header_libs: [
+                "libbufferhub_headers",
+                "libdvr_headers",
+            ],
+            exclude_shared_libs: [
+                "android.frameworks.bufferhub@1.0",
+                "libpdx_default_transport",
+            ],
+        },
+    },
+
     header_libs: [
         "libbase_headers",
+        "libbufferhub_headers",
+        "libdvr_headers",
         "libnativebase_headers",
+        "libnativewindow_headers",
         "libhardware_headers",
         "libui_headers",
         "libpdx_headers",
@@ -116,6 +153,7 @@
     export_header_lib_headers: [
         "libbase_headers",
         "libnativebase_headers",
+        "libnativewindow_headers",
         "libhardware_headers",
         "libui_headers",
     ],
@@ -127,9 +165,23 @@
     vendor_available: true,
     target: {
         vendor: {
+            cflags: ["-DLIBUI_IN_VNDK"],
             override_export_include_dirs: ["include_vndk"],
         },
     },
+    header_libs: [
+        "libnativewindow_headers",
+    ],
+    export_header_lib_headers: [
+        "libnativewindow_headers",
+    ],
+}
+
+// defaults to enable VALIDATE_REGIONS traces
+cc_defaults {
+    name: "libui-validate-regions-defaults",
+    shared_libs: ["libutilscallstack"],
+    cflags: ["-DVALIDATE_REGIONS"],
 }
 
 subdirs = [
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
new file mode 100644
index 0000000..da91a97
--- /dev/null
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <poll.h>
+
+#include <android-base/unique_fd.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <log/log.h>
+#include <ui/BufferHubBuffer.h>
+#include <ui/BufferHubDefs.h>
+#include <utils/Trace.h>
+
+using ::android::base::unique_fd;
+using ::android::BufferHubDefs::isAnyClientAcquired;
+using ::android::BufferHubDefs::isAnyClientGained;
+using ::android::BufferHubDefs::isClientAcquired;
+using ::android::BufferHubDefs::isClientGained;
+using ::android::BufferHubDefs::isClientPosted;
+using ::android::BufferHubDefs::isClientReleased;
+using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
+using ::android::frameworks::bufferhub::V1_0::BufferTraits;
+using ::android::frameworks::bufferhub::V1_0::IBufferClient;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
+
+namespace android {
+
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::create(uint32_t width, uint32_t height,
+                                                         uint32_t layerCount, uint32_t format,
+                                                         uint64_t usage, size_t userMetadataSize) {
+    auto buffer = std::unique_ptr<BufferHubBuffer>(
+            new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
+    return buffer->isValid() ? std::move(buffer) : nullptr;
+}
+
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::import(const sp<NativeHandle>& token) {
+    if (token == nullptr || token.get() == nullptr) {
+        ALOGE("%s: token cannot be nullptr!", __FUNCTION__);
+        return nullptr;
+    }
+
+    auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token));
+    return buffer->isValid() ? std::move(buffer) : nullptr;
+}
+
+BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+                                 uint32_t format, uint64_t usage, size_t userMetadataSize) {
+    ATRACE_CALL();
+    ALOGD("%s: width=%u height=%u layerCount=%u, format=%u "
+          "usage=%" PRIx64 " mUserMetadataSize=%zu",
+          __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize);
+
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    if (bufferhub.get() == nullptr) {
+        ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+        return;
+    }
+
+    AHardwareBuffer_Desc aDesc = {width, height,         layerCount,   format,
+                                  usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+    HardwareBufferDescription desc;
+    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+    BufferHubStatus ret;
+    sp<IBufferClient> client;
+    BufferTraits bufferTraits;
+    IBufferHub::allocateBuffer_cb allocCb = [&](const auto& status, const auto& outClient,
+                                                const auto& outTraits) {
+        ret = status;
+        client = std::move(outClient);
+        bufferTraits = std::move(outTraits);
+    };
+
+    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), allocCb).isOk()) {
+        ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
+        return;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret);
+        return;
+    } else if (client == nullptr) {
+        ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__);
+        return;
+    }
+
+    const int importRet = initWithBufferTraits(bufferTraits);
+    if (importRet < 0) {
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+        client->close();
+    }
+    mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::BufferHubBuffer(const sp<NativeHandle>& token) {
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    if (bufferhub.get() == nullptr) {
+        ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+        return;
+    }
+
+    BufferHubStatus ret;
+    sp<IBufferClient> client;
+    BufferTraits bufferTraits;
+    IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
+                                               const auto& outTraits) {
+        ret = status;
+        client = std::move(outClient);
+        bufferTraits = std::move(outTraits);
+    };
+
+    // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
+    // transfer.
+    if (!bufferhub->importBuffer(hidl_handle(token.get()->handle()), importCb).isOk()) {
+        ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
+        return;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret);
+        return;
+    } else if (client == nullptr) {
+        ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__);
+        return;
+    }
+
+    const int importRet = initWithBufferTraits(bufferTraits);
+    if (importRet < 0) {
+        ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+        client->close();
+    }
+    mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::~BufferHubBuffer() {
+    // Close buffer client to avoid possible race condition: user could first duplicate and hold
+    // token with the original buffer gone, and then try to import the token. The close function
+    // will explicitly invalidate the token to avoid this.
+    if (mBufferClient != nullptr) {
+        if (!mBufferClient->close().isOk()) {
+            ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__);
+        }
+    }
+}
+
+int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
+    ATRACE_CALL();
+
+    if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) {
+        ALOGE("%s: missing buffer info handle.", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) {
+        ALOGE("%s: missing gralloc handle.", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    // Import fds. Dup fds because hidl_handle owns the fds.
+    unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
+    mMetadata = BufferHubMetadata::import(std::move(ashmemFd));
+    if (!mMetadata.isValid()) {
+        ALOGE("%s: Received an invalid metadata.", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    mEventFd = BufferHubEventFd(fcntl(bufferTraits.bufferInfo->data[1], F_DUPFD_CLOEXEC, 0));
+    if (!mEventFd.isValid()) {
+        ALOGE("%s: Received ad invalid event fd.", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    int bufferId = bufferTraits.bufferInfo->data[2];
+    if (bufferId < 0) {
+        ALOGE("%s: Received an invalid (negative) id.", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    uint32_t clientBitMask;
+    memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[3], sizeof(clientBitMask));
+    if (clientBitMask == 0U) {
+        ALOGE("%s: Received an invalid client state mask.", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    uint32_t userMetadataSize;
+    memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[4], sizeof(userMetadataSize));
+    if (mMetadata.userMetadataSize() != userMetadataSize) {
+        ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
+              userMetadataSize, mMetadata.userMetadataSize());
+        return -EINVAL;
+    }
+
+    size_t metadataSize = static_cast<size_t>(mMetadata.metadataSize());
+    if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
+        ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
+        return -EINVAL;
+    }
+
+    // Populate shortcuts to the atomics in metadata.
+    auto metadataHeader = mMetadata.metadataHeader();
+    mBufferState = &metadataHeader->bufferState;
+    mFenceState = &metadataHeader->fenceState;
+    mActiveClientsBitMask = &metadataHeader->activeClientsBitMask;
+    // The C++ standard recommends (but does not require) that lock-free atomic operations are
+    // also address-free, that is, suitable for communication between processes using shared
+    // memory.
+    LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(mBufferState) ||
+                                !std::atomic_is_lock_free(mFenceState) ||
+                                !std::atomic_is_lock_free(mActiveClientsBitMask),
+                        "Atomic variables in ashmen are not lock free.");
+
+    // Import the buffer: We only need to hold on the native_handle_t here so that
+    // GraphicBuffer instance can be created in future.
+    mBufferHandle = std::move(bufferTraits.bufferHandle);
+    memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc));
+
+    mId = bufferId;
+    mClientStateMask = clientBitMask;
+
+    // TODO(b/112012161) Set up shared fences.
+    ALOGD("%s: id=%d, mBufferState=%" PRIx32 ".", __FUNCTION__, mId,
+          mBufferState->load(std::memory_order_acquire));
+    return 0;
+}
+
+int BufferHubBuffer::gain() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    if (isClientGained(currentBufferState, mClientStateMask)) {
+        ALOGV("%s: Buffer is already gained by this client %" PRIx32 ".", __FUNCTION__,
+              mClientStateMask);
+        return 0;
+    }
+    do {
+        if (isAnyClientGained(currentBufferState & (~mClientStateMask)) ||
+            isAnyClientAcquired(currentBufferState)) {
+            ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
+                  __FUNCTION__, mId, mClientStateMask, currentBufferState);
+            return -EBUSY;
+        }
+        // Change the buffer state to gained state, whose value happens to be the same as
+        // mClientStateMask.
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, mClientStateMask,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence.
+    return 0;
+}
+
+int BufferHubBuffer::post() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    uint32_t updatedBufferState = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
+    do {
+        if (!isClientGained(currentBufferState, mClientStateMask)) {
+            ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
+                  "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
+                  __FUNCTION__, mId, mClientStateMask, currentBufferState);
+            return -EBUSY;
+        }
+        // Set the producer client buffer state to released, other clients' buffer state to posted.
+        // Post to all existing and non-existing clients.
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence if needed.
+    return 0;
+}
+
+int BufferHubBuffer::acquire() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    if (isClientAcquired(currentBufferState, mClientStateMask)) {
+        ALOGV("%s: Buffer is already acquired by this client %" PRIx32 ".", __FUNCTION__,
+              mClientStateMask);
+        return 0;
+    }
+    uint32_t updatedBufferState = 0U;
+    do {
+        if (!isClientPosted(currentBufferState, mClientStateMask)) {
+            ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
+                  "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
+                  __FUNCTION__, mId, mClientStateMask, currentBufferState);
+            return -EBUSY;
+        }
+        // Change the buffer state for this consumer from posted to acquired.
+        updatedBufferState = currentBufferState ^ mClientStateMask;
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence.
+    return 0;
+}
+
+int BufferHubBuffer::release() {
+    uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire);
+    if (isClientReleased(currentBufferState, mClientStateMask)) {
+        ALOGV("%s: Buffer is already released by this client %" PRIx32 ".", __FUNCTION__,
+              mClientStateMask);
+        return 0;
+    }
+    uint32_t updatedBufferState = 0U;
+    do {
+        updatedBufferState = currentBufferState & (~mClientStateMask);
+    } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState,
+                                                  std::memory_order_acq_rel,
+                                                  std::memory_order_acquire));
+    // TODO(b/119837586): Update fence state and return GPU fence if needed.
+    return 0;
+}
+
+bool BufferHubBuffer::isReleased() const {
+    return (mBufferState->load(std::memory_order_acquire) &
+            mActiveClientsBitMask->load(std::memory_order_acquire)) == 0;
+}
+
+bool BufferHubBuffer::isValid() const {
+    return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
+            mEventFd.get() >= 0 && mMetadata.isValid() && mBufferClient != nullptr;
+}
+
+sp<NativeHandle> BufferHubBuffer::duplicate() {
+    if (mBufferClient == nullptr) {
+        ALOGE("%s: missing BufferClient!", __FUNCTION__);
+        return nullptr;
+    }
+
+    hidl_handle token;
+    BufferHubStatus ret;
+    IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) {
+        token = std::move(outToken);
+        ret = status;
+    };
+
+    if (!mBufferClient->duplicate(dupCb).isOk()) {
+        ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
+        return nullptr;
+    } else if (ret != BufferHubStatus::NO_ERROR) {
+        ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret);
+        return nullptr;
+    } else if (token.getNativeHandle() == nullptr) {
+        ALOGE("%s: duplicate got null token.", __FUNCTION__);
+        return nullptr;
+    }
+
+    return NativeHandle::create(native_handle_clone(token.getNativeHandle()), /*ownsHandle=*/true);
+}
+
+} // namespace android
diff --git a/libs/ui/BufferHubEventFd.cpp b/libs/ui/BufferHubEventFd.cpp
new file mode 100644
index 0000000..bffc2ca
--- /dev/null
+++ b/libs/ui/BufferHubEventFd.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/eventfd.h>
+
+#include <log/log.h>
+#include <ui/BufferHubEventFd.h>
+
+namespace android {
+
+BufferHubEventFd::BufferHubEventFd() : mFd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) {}
+
+BufferHubEventFd::BufferHubEventFd(int fd) : mFd(fd) {}
+
+status_t BufferHubEventFd::signal() const {
+    if (!isValid()) {
+        ALOGE("%s: cannot signal an invalid eventfd.", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    eventfd_write(mFd.get(), 1);
+    return OK;
+}
+
+status_t BufferHubEventFd::clear() const {
+    if (!isValid()) {
+        ALOGE("%s: cannot clear an invalid eventfd.", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    eventfd_t value;
+    eventfd_read(mFd.get(), &value);
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/ui/BufferHubMetadata.cpp b/libs/ui/BufferHubMetadata.cpp
new file mode 100644
index 0000000..05bc7dd
--- /dev/null
+++ b/libs/ui/BufferHubMetadata.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <limits>
+
+#include <cutils/ashmem.h>
+#include <log/log.h>
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+
+namespace {
+
+static const int kAshmemProt = PROT_READ | PROT_WRITE;
+
+} // namespace
+
+using BufferHubDefs::kMetadataHeaderSize;
+using BufferHubDefs::MetadataHeader;
+
+/* static */
+BufferHubMetadata BufferHubMetadata::create(size_t userMetadataSize) {
+    // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it
+    // cannot overflow uint32_t.
+    if (userMetadataSize >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
+        ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", userMetadataSize);
+        return {};
+    }
+
+    const size_t metadataSize = userMetadataSize + kMetadataHeaderSize;
+    int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadataSize);
+    if (fd < 0) {
+        ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
+        return {};
+    }
+
+    // Hand over the ownership of the fd to a unique_fd immediately after the successful
+    // return of ashmem_create_region. The ashmemFd is going to own the fd and to prevent fd
+    // leaks during error handling.
+    unique_fd ashmemFd{fd};
+
+    if (ashmem_set_prot_region(ashmemFd.get(), kAshmemProt) != 0) {
+        ALOGE("BufferHubMetadata::Create: failed to set protect region.");
+        return {};
+    }
+
+    return BufferHubMetadata::import(std::move(ashmemFd));
+}
+
+/* static */
+BufferHubMetadata BufferHubMetadata::import(unique_fd ashmemFd) {
+    if (!ashmem_valid(ashmemFd.get())) {
+        ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
+        return {};
+    }
+
+    size_t metadataSize = static_cast<size_t>(ashmem_get_size_region(ashmemFd.get()));
+    size_t userMetadataSize = metadataSize - kMetadataHeaderSize;
+
+    // Note that here the buffer state is mapped from shared memory as an atomic object. The
+    // std::atomic's constructor will not be called so that the original value stored in the memory
+    // region can be preserved.
+    auto metadataHeader = static_cast<MetadataHeader*>(mmap(nullptr, metadataSize, kAshmemProt,
+                                                            MAP_SHARED, ashmemFd.get(),
+                                                            /*offset=*/0));
+    if (metadataHeader == nullptr) {
+        ALOGE("BufferHubMetadata::Import: failed to map region.");
+        return {};
+    }
+
+    return BufferHubMetadata(userMetadataSize, std::move(ashmemFd), metadataHeader);
+}
+
+BufferHubMetadata::BufferHubMetadata(size_t userMetadataSize, unique_fd ashmemFd,
+                                     MetadataHeader* metadataHeader)
+      : mUserMetadataSize(userMetadataSize),
+        mAshmemFd(std::move(ashmemFd)),
+        mMetadataHeader(metadataHeader) {}
+
+BufferHubMetadata::~BufferHubMetadata() {
+    if (mMetadataHeader != nullptr) {
+        int ret = munmap(mMetadataHeader, metadataSize());
+        ALOGE_IF(ret != 0,
+                 "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno);
+        mMetadataHeader = nullptr;
+    }
+}
+
+} // namespace android
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 5b4bf23..7a14af1 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -351,13 +351,12 @@
     };
 }
 
-std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
-        const ColorSpace& src, const ColorSpace& dst) {
-
+std::unique_ptr<float3[]> ColorSpace::createLUT(uint32_t size, const ColorSpace& src,
+                                                const ColorSpace& dst) {
     size = clamp(size, 2u, 256u);
     float m = 1.0f / float(size - 1);
 
-    std::unique_ptr<float3> lut(new float3[size * size * size]);
+    std::unique_ptr<float3[]> lut(new float3[size * size * size]);
     float3* data = lut.get();
 
     ColorSpaceConnector connector(src, dst);
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 61df02d..ee06d93 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -234,6 +234,9 @@
         case ColorMode::BT2020:
             return std::string("ColorMode::BT2020");
 
+        case ColorMode::DISPLAY_BT2020:
+            return std::string("ColorMode::DISPLAY_BT2020");
+
         case ColorMode::BT2100_PQ:
             return std::string("ColorMode::BT2100_PQ");
 
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index ff53aa8..4ce891e 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -109,25 +109,25 @@
         return SIGNAL_TIME_INVALID;
     }
 
-    struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd);
-    if (finfo == NULL) {
-        ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd.get());
+    struct sync_file_info* finfo = sync_file_info(mFenceFd);
+    if (finfo == nullptr) {
+        ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get());
         return SIGNAL_TIME_INVALID;
     }
     if (finfo->status != 1) {
-        sync_fence_info_free(finfo);
+        sync_file_info_free(finfo);
         return SIGNAL_TIME_PENDING;
     }
 
-    struct sync_pt_info* pinfo = NULL;
     uint64_t timestamp = 0;
-    while ((pinfo = sync_pt_info(finfo, pinfo)) != NULL) {
-        if (pinfo->timestamp_ns > timestamp) {
-            timestamp = pinfo->timestamp_ns;
+    struct sync_fence_info* pinfo = sync_get_fence_info(finfo);
+    for (size_t i = 0; i < finfo->num_fences; i++) {
+        if (pinfo[i].timestamp_ns > timestamp) {
+            timestamp = pinfo[i].timestamp_ns;
         }
     }
-    sync_fence_info_free(finfo);
 
+    sync_file_info_free(finfo);
     return nsecs_t(timestamp);
 }
 
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index 1414766..bdfe04b 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -33,18 +33,6 @@
 
 const auto FenceTime::NO_FENCE = std::make_shared<FenceTime>(Fence::NO_FENCE);
 
-void* FenceTime::operator new(size_t byteCount) noexcept {
-    void *p = nullptr;
-    if (posix_memalign(&p, alignof(FenceTime), byteCount)) {
-        return nullptr;
-    }
-    return p;
-}
-
-void FenceTime::operator delete(void *p) {
-    free(p);
-}
-
 FenceTime::FenceTime(const sp<Fence>& fence)
   : mState(((fence.get() != nullptr) && fence->isValid()) ?
             State::VALID : State::INVALID),
@@ -291,8 +279,8 @@
 }
 
 void FenceTimeline::updateSignalTimes() {
+    std::lock_guard<std::mutex> lock(mMutex);
     while (!mQueue.empty()) {
-        std::lock_guard<std::mutex> lock(mMutex);
         std::shared_ptr<FenceTime> fence = mQueue.front().lock();
         if (!fence) {
             // The shared_ptr no longer exists and no one cares about the
diff --git a/libs/ui/Gralloc.cpp b/libs/ui/Gralloc.cpp
new file mode 100644
index 0000000..8e09a13
--- /dev/null
+++ b/libs/ui/Gralloc.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gralloc"
+
+#include <ui/Gralloc.h>
+
+namespace android {
+
+GrallocMapper::~GrallocMapper() {}
+
+GrallocAllocator::~GrallocAllocator() {}
+
+} // namespace android
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index b92cbf3..5dc4530 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -27,9 +27,15 @@
 #include <sync/sync.h>
 #pragma clang diagnostic pop
 
-namespace android {
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V2_0::Error;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using android::hardware::graphics::mapper::V2_1::IMapper;
 
-namespace Gralloc2 {
+namespace android {
 
 namespace {
 
@@ -39,12 +45,9 @@
     static const uint64_t valid10UsageBits = []() -> uint64_t {
         using hardware::graphics::common::V1_0::BufferUsage;
         uint64_t bits = 0;
-        for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+        for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
             bits = bits | bit;
         }
-        // TODO(b/72323293, b/72703005): Remove these additional bits
-        bits = bits | (1 << 10) | (1 << 13);
-
         return bits;
     }();
     return valid10UsageBits;
@@ -54,7 +57,7 @@
     static const uint64_t valid11UsageBits = []() -> uint64_t {
         using hardware::graphics::common::V1_1::BufferUsage;
         uint64_t bits = 0;
-        for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+        for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
             bits = bits | bit;
         }
         return bits;
@@ -62,17 +65,26 @@
     return valid11UsageBits;
 }
 
+static inline IMapper::Rect sGralloc2Rect(const Rect& rect) {
+    IMapper::Rect outRect{};
+    outRect.left = rect.left;
+    outRect.top = rect.top;
+    outRect.width = rect.width();
+    outRect.height = rect.height();
+    return outRect;
+}
+
 }  // anonymous namespace
 
-void Mapper::preload() {
+void Gralloc2Mapper::preload() {
     android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
 }
 
-Mapper::Mapper()
-{
+Gralloc2Mapper::Gralloc2Mapper() {
     mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
     if (mMapper == nullptr) {
-        LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+        ALOGW("mapper 2.x is not supported");
+        return;
     }
     if (mMapper->isRemote()) {
         LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
@@ -82,30 +94,37 @@
     mMapperV2_1 = IMapper::castFrom(mMapper);
 }
 
-Gralloc2::Error Mapper::validateBufferDescriptorInfo(
-        const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+bool Gralloc2Mapper::isLoaded() const {
+    return mMapper != nullptr;
+}
+
+status_t Gralloc2Mapper::validateBufferDescriptorInfo(
+        IMapper::BufferDescriptorInfo* descriptorInfo) const {
     uint64_t validUsageBits = getValid10UsageBits();
     if (mMapperV2_1 != nullptr) {
         validUsageBits = validUsageBits | getValid11UsageBits();
     }
 
-    if (descriptorInfo.usage & ~validUsageBits) {
+    if (descriptorInfo->usage & ~validUsageBits) {
         ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
-              descriptorInfo.usage & ~validUsageBits);
-        return Error::BAD_VALUE;
+              descriptorInfo->usage & ~validUsageBits);
+        return BAD_VALUE;
     }
-    return Error::NONE;
+    return NO_ERROR;
 }
 
-Error Mapper::createDescriptor(
-        const IMapper::BufferDescriptorInfo& descriptorInfo,
-        BufferDescriptor* outDescriptor) const
-{
-    Error error = validateBufferDescriptorInfo(descriptorInfo);
-    if (error != Error::NONE) {
-        return error;
+status_t Gralloc2Mapper::createDescriptor(void* bufferDescriptorInfo,
+                                          void* outBufferDescriptor) const {
+    IMapper::BufferDescriptorInfo* descriptorInfo =
+            static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+    BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+    status_t status = validateBufferDescriptorInfo(descriptorInfo);
+    if (status != NO_ERROR) {
+        return status;
     }
 
+    Error error;
     auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor)
                    {
                        error = tmpError;
@@ -118,24 +137,23 @@
 
     hardware::Return<void> ret;
     if (mMapperV2_1 != nullptr) {
-        ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb);
+        ret = mMapperV2_1->createDescriptor_2_1(*descriptorInfo, hidl_cb);
     } else {
         const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = {
-            descriptorInfo.width,
-            descriptorInfo.height,
-            descriptorInfo.layerCount,
-            static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format),
-            descriptorInfo.usage,
+                descriptorInfo->width,
+                descriptorInfo->height,
+                descriptorInfo->layerCount,
+                static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo->format),
+                descriptorInfo->usage,
         };
         ret = mMapper->createDescriptor(info, hidl_cb);
     }
 
-    return (ret.isOk()) ? error : kTransactionError;
+    return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
 }
 
-Error Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
-        buffer_handle_t* outBufferHandle) const
-{
+status_t Gralloc2Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+                                      buffer_handle_t* outBufferHandle) const {
     Error error;
     auto ret = mMapper->importBuffer(rawHandle,
             [&](const auto& tmpError, const auto& tmpBuffer)
@@ -148,11 +166,10 @@
                 *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
             });
 
-    return (ret.isOk()) ? error : kTransactionError;
+    return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
 }
 
-void Mapper::freeBuffer(buffer_handle_t bufferHandle) const
-{
+void Gralloc2Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
     auto ret = mMapper->freeBuffer(buffer);
 
@@ -161,23 +178,29 @@
             buffer, error);
 }
 
-Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
-        const IMapper::BufferDescriptorInfo& descriptorInfo,
-        uint32_t stride) const
-{
+status_t Gralloc2Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+                                            uint32_t height, android::PixelFormat format,
+                                            uint32_t layerCount, uint64_t usage,
+                                            uint32_t stride) const {
     if (mMapperV2_1 == nullptr) {
-        return Error::NONE;
+        return NO_ERROR;
     }
 
+    IMapper::BufferDescriptorInfo descriptorInfo = {};
+    descriptorInfo.width = width;
+    descriptorInfo.height = height;
+    descriptorInfo.layerCount = layerCount;
+    descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+    descriptorInfo.usage = usage;
+
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
     auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
 
-    return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+    return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
 }
 
-void Mapper::getTransportSize(buffer_handle_t bufferHandle,
-        uint32_t* outNumFds, uint32_t* outNumInts) const
-{
+void Gralloc2Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+                                      uint32_t* outNumInts) const {
     *outNumFds = uint32_t(bufferHandle->numFds);
     *outNumInts = uint32_t(bufferHandle->numInts);
 
@@ -198,19 +221,24 @@
                 *outNumInts = tmpNumInts;
             });
 
-    if (!ret.isOk()) {
-        error = kTransactionError;
-    }
-    ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
-            buffer, error);
+    error = (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
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                              int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                              int32_t* outBytesPerStride) const {
+    if (outBytesPerPixel) {
+        *outBytesPerPixel = -1;
+    }
+    if (outBytesPerStride) {
+        *outBytesPerStride = -1;
+    }
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
+    IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
     // put acquireFence in a hidl_handle
     hardware::hidl_handle acquireFenceHandle;
     NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -237,15 +265,19 @@
         close(acquireFence);
     }
 
-    return (ret.isOk()) ? error : kTransactionError;
+    error = (ret.isOk()) ? error : kTransactionError;
+
+    ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+    return static_cast<status_t>(error);
 }
 
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
-        const IMapper::Rect& accessRegion,
-        int acquireFence, YCbCrLayout* outLayout) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                              int acquireFence, android_ycbcr* ycbcr) const {
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
+    IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
     // put acquireFence in a hidl_handle
     hardware::hidl_handle acquireFenceHandle;
     NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -255,6 +287,7 @@
         acquireFenceHandle = h;
     }
 
+    YCbCrLayout layout;
     Error error;
     auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion,
             acquireFenceHandle,
@@ -265,19 +298,27 @@
                     return;
                 }
 
-                *outLayout = tmpLayout;
+                layout = tmpLayout;
             });
 
+    if (error == Error::NONE) {
+        ycbcr->y = layout.y;
+        ycbcr->cb = layout.cb;
+        ycbcr->cr = layout.cr;
+        ycbcr->ystride = static_cast<size_t>(layout.yStride);
+        ycbcr->cstride = static_cast<size_t>(layout.cStride);
+        ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+    }
+
     // we own acquireFence even on errors
     if (acquireFence >= 0) {
         close(acquireFence);
     }
 
-    return (ret.isOk()) ? error : kTransactionError;
+    return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
 }
 
-int Mapper::unlock(buffer_handle_t bufferHandle) const
-{
+int Gralloc2Mapper::unlock(buffer_handle_t bufferHandle) const {
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
     int releaseFence = -1;
@@ -302,10 +343,7 @@
                 }
             });
 
-    if (!ret.isOk()) {
-        error = kTransactionError;
-    }
-
+    error = (ret.isOk()) ? error : kTransactionError;
     if (error != Error::NONE) {
         ALOGE("unlock(%p) failed with %d", buffer, error);
     }
@@ -313,17 +351,25 @@
     return releaseFence;
 }
 
-Allocator::Allocator(const Mapper& mapper)
-    : mMapper(mapper)
-{
+status_t Gralloc2Mapper::isSupported(uint32_t /*width*/, uint32_t /*height*/,
+                                     android::PixelFormat /*format*/, uint32_t /*layerCount*/,
+                                     uint64_t /*usage*/, bool* /*outSupported*/) const {
+    return INVALID_OPERATION;
+}
+
+Gralloc2Allocator::Gralloc2Allocator(const Gralloc2Mapper& mapper) : mMapper(mapper) {
     mAllocator = IAllocator::getService();
     if (mAllocator == nullptr) {
-        LOG_ALWAYS_FATAL("gralloc-alloc is missing");
+        ALOGW("allocator 2.x is not supported");
+        return;
     }
 }
 
-std::string Allocator::dumpDebugInfo() const
-{
+bool Gralloc2Allocator::isLoaded() const {
+    return mAllocator != nullptr;
+}
+
+std::string Gralloc2Allocator::dumpDebugInfo() const {
     std::string debugInfo;
 
     mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) {
@@ -333,40 +379,51 @@
     return debugInfo;
 }
 
-Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count,
-        uint32_t* outStride, buffer_handle_t* outBufferHandles) const
-{
-    Error error;
-    auto ret = mAllocator->allocate(descriptor, count,
-            [&](const auto& tmpError, const auto& tmpStride,
-                const auto& tmpBuffers) {
-                error = tmpError;
-                if (tmpError != Error::NONE) {
-                    return;
-                }
+status_t Gralloc2Allocator::allocate(uint32_t width, uint32_t height, PixelFormat format,
+                                     uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+                                     uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+    IMapper::BufferDescriptorInfo descriptorInfo = {};
+    descriptorInfo.width = width;
+    descriptorInfo.height = height;
+    descriptorInfo.layerCount = layerCount;
+    descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+    descriptorInfo.usage = usage;
 
-                // import buffers
-                for (uint32_t i = 0; i < count; i++) {
-                    error = mMapper.importBuffer(tmpBuffers[i],
-                            &outBufferHandles[i]);
-                    if (error != Error::NONE) {
-                        for (uint32_t j = 0; j < i; j++) {
-                            mMapper.freeBuffer(outBufferHandles[j]);
-                            outBufferHandles[j] = nullptr;
-                        }
-                        return;
-                    }
-                }
+    BufferDescriptor descriptor;
+    status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+                                              static_cast<void*>(&descriptor));
+    if (error != NO_ERROR) {
+        return error;
+    }
 
-                *outStride = tmpStride;
-            });
+    auto ret = mAllocator->allocate(descriptor, bufferCount,
+                                    [&](const auto& tmpError, const auto& tmpStride,
+                                        const auto& tmpBuffers) {
+                                        error = static_cast<status_t>(tmpError);
+                                        if (tmpError != Error::NONE) {
+                                            return;
+                                        }
+
+                                        // import buffers
+                                        for (uint32_t i = 0; i < bufferCount; i++) {
+                                            error = mMapper.importBuffer(tmpBuffers[i],
+                                                                         &outBufferHandles[i]);
+                                            if (error != NO_ERROR) {
+                                                for (uint32_t j = 0; j < i; j++) {
+                                                    mMapper.freeBuffer(outBufferHandles[j]);
+                                                    outBufferHandles[j] = nullptr;
+                                                }
+                                                return;
+                                            }
+                                        }
+
+                                        *outStride = tmpStride;
+                                    });
 
     // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
     hardware::IPCThreadState::self()->flushCommands();
 
-    return (ret.isOk()) ? error : kTransactionError;
+    return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
 }
 
-} // namespace Gralloc2
-
 } // namespace android
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
new file mode 100644
index 0000000..eb43765
--- /dev/null
+++ b/libs/ui/Gralloc3.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gralloc3"
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/Gralloc3.h>
+
+#include <inttypes.h>
+#include <log/log.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#include <sync/sync.h>
+#pragma clang diagnostic pop
+
+using android::hardware::graphics::allocator::V3_0::IAllocator;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V3_0::Error;
+using android::hardware::graphics::mapper::V3_0::IMapper;
+using android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+
+namespace android {
+
+namespace {
+
+static constexpr Error kTransactionError = Error::NO_RESOURCES;
+
+uint64_t getValidUsageBits() {
+    static const uint64_t validUsageBits = []() -> uint64_t {
+        uint64_t bits = 0;
+        for (const auto bit :
+             hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
+            bits = bits | bit;
+        }
+        return bits;
+    }();
+    return validUsageBits;
+}
+
+static inline IMapper::Rect sGralloc3Rect(const Rect& rect) {
+    IMapper::Rect outRect{};
+    outRect.left = rect.left;
+    outRect.top = rect.top;
+    outRect.width = rect.width();
+    outRect.height = rect.height();
+    return outRect;
+}
+static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height,
+                                         android::PixelFormat format, uint32_t layerCount,
+                                         uint64_t usage,
+                                         IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+    outDescriptorInfo->width = width;
+    outDescriptorInfo->height = height;
+    outDescriptorInfo->layerCount = layerCount;
+    outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+    outDescriptorInfo->usage = usage;
+}
+
+} // anonymous namespace
+
+void Gralloc3Mapper::preload() {
+    android::hardware::preloadPassthroughService<IMapper>();
+}
+
+Gralloc3Mapper::Gralloc3Mapper() {
+    mMapper = IMapper::getService();
+    if (mMapper == nullptr) {
+        ALOGW("mapper 3.x is not supported");
+        return;
+    }
+    if (mMapper->isRemote()) {
+        LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
+    }
+}
+
+bool Gralloc3Mapper::isLoaded() const {
+    return mMapper != nullptr;
+}
+
+status_t Gralloc3Mapper::validateBufferDescriptorInfo(
+        IMapper::BufferDescriptorInfo* descriptorInfo) const {
+    uint64_t validUsageBits = getValidUsageBits();
+
+    if (descriptorInfo->usage & ~validUsageBits) {
+        ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+              descriptorInfo->usage & ~validUsageBits);
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
+status_t Gralloc3Mapper::createDescriptor(void* bufferDescriptorInfo,
+                                          void* outBufferDescriptor) const {
+    IMapper::BufferDescriptorInfo* descriptorInfo =
+            static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+    BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+    status_t status = validateBufferDescriptorInfo(descriptorInfo);
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    Error error;
+    auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+        *outDescriptor = tmpDescriptor;
+    };
+
+    hardware::Return<void> ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb);
+
+    return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+status_t Gralloc3Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+                                      buffer_handle_t* outBufferHandle) const {
+    Error error;
+    auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+        *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
+    });
+
+    return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+void Gralloc3Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapper->freeBuffer(buffer);
+
+    auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+    ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+                                            uint32_t height, android::PixelFormat format,
+                                            uint32_t layerCount, uint64_t usage,
+                                            uint32_t stride) const {
+    IMapper::BufferDescriptorInfo descriptorInfo;
+    sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+
+    return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
+}
+
+void Gralloc3Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+                                      uint32_t* outNumInts) const {
+    *outNumFds = uint32_t(bufferHandle->numFds);
+    *outNumInts = uint32_t(bufferHandle->numInts);
+
+    Error error;
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapper->getTransportSize(buffer,
+                                         [&](const auto& tmpError, const auto& tmpNumFds,
+                                             const auto& tmpNumInts) {
+                                             error = tmpError;
+                                             if (error != Error::NONE) {
+                                                 return;
+                                             }
+                                             *outNumFds = tmpNumFds;
+                                             *outNumInts = tmpNumInts;
+                                         });
+
+    error = (ret.isOk()) ? error : kTransactionError;
+
+    ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                              int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                              int32_t* outBytesPerStride) const {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+    // put acquireFence in a hidl_handle
+    hardware::hidl_handle acquireFenceHandle;
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    Error error;
+    auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
+                             [&](const auto& tmpError, const auto& tmpData,
+                                 const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) {
+                                 error = tmpError;
+                                 if (error != Error::NONE) {
+                                     return;
+                                 }
+                                 *outData = tmpData;
+                                 if (outBytesPerPixel) {
+                                     *outBytesPerPixel = tmpBytesPerPixel;
+                                 }
+                                 if (outBytesPerStride) {
+                                     *outBytesPerStride = tmpBytesPerStride;
+                                 }
+                             });
+
+    // we own acquireFence even on errors
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    error = (ret.isOk()) ? error : kTransactionError;
+
+    ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+    return static_cast<status_t>(error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                              int acquireFence, android_ycbcr* ycbcr) const {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+    // put acquireFence in a hidl_handle
+    hardware::hidl_handle acquireFenceHandle;
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    YCbCrLayout layout;
+    Error error;
+    auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
+                                  [&](const auto& tmpError, const auto& tmpLayout) {
+                                      error = tmpError;
+                                      if (error != Error::NONE) {
+                                          return;
+                                      }
+
+                                      layout = tmpLayout;
+                                  });
+
+    if (error == Error::NONE) {
+        ycbcr->y = layout.y;
+        ycbcr->cb = layout.cb;
+        ycbcr->cr = layout.cr;
+        ycbcr->ystride = static_cast<size_t>(layout.yStride);
+        ycbcr->cstride = static_cast<size_t>(layout.cStride);
+        ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+    }
+
+    // we own acquireFence even on errors
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+int Gralloc3Mapper::unlock(buffer_handle_t bufferHandle) const {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    int releaseFence = -1;
+    Error error;
+    auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        error = tmpError;
+        if (error != Error::NONE) {
+            return;
+        }
+
+        auto fenceHandle = tmpReleaseFence.getNativeHandle();
+        if (fenceHandle && fenceHandle->numFds == 1) {
+            int fd = dup(fenceHandle->data[0]);
+            if (fd >= 0) {
+                releaseFence = fd;
+            } else {
+                ALOGD("failed to dup unlock release fence");
+                sync_wait(fenceHandle->data[0], -1);
+            }
+        }
+    });
+
+    if (!ret.isOk()) {
+        error = kTransactionError;
+    }
+
+    if (error != Error::NONE) {
+        ALOGE("unlock(%p) failed with %d", buffer, error);
+    }
+
+    return releaseFence;
+}
+
+status_t Gralloc3Mapper::isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+                                     uint32_t layerCount, uint64_t usage,
+                                     bool* outSupported) const {
+    IMapper::BufferDescriptorInfo descriptorInfo;
+    sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+    Error error;
+    auto ret = mMapper->isSupported(descriptorInfo,
+                                    [&](const auto& tmpError, const auto& tmpSupported) {
+                                        error = tmpError;
+                                        if (error != Error::NONE) {
+                                            return;
+                                        }
+                                        if (outSupported) {
+                                            *outSupported = tmpSupported;
+                                        }
+                                    });
+
+    if (!ret.isOk()) {
+        error = kTransactionError;
+    }
+
+    if (error != Error::NONE) {
+        ALOGE("isSupported(%u, %u, %d, %u, ...) failed with %d", width, height, format, layerCount,
+              error);
+    }
+
+    return static_cast<status_t>(error);
+}
+
+Gralloc3Allocator::Gralloc3Allocator(const Gralloc3Mapper& mapper) : mMapper(mapper) {
+    mAllocator = IAllocator::getService();
+    if (mAllocator == nullptr) {
+        ALOGW("allocator 3.x is not supported");
+        return;
+    }
+}
+
+bool Gralloc3Allocator::isLoaded() const {
+    return mAllocator != nullptr;
+}
+
+std::string Gralloc3Allocator::dumpDebugInfo() const {
+    std::string debugInfo;
+
+    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+    return debugInfo;
+}
+
+status_t Gralloc3Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
+                                     uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+                                     uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+    IMapper::BufferDescriptorInfo descriptorInfo;
+    sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+    BufferDescriptor descriptor;
+    status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+                                              static_cast<void*>(&descriptor));
+    if (error != NO_ERROR) {
+        return error;
+    }
+
+    auto ret = mAllocator->allocate(descriptor, bufferCount,
+                                    [&](const auto& tmpError, const auto& tmpStride,
+                                        const auto& tmpBuffers) {
+                                        error = static_cast<status_t>(tmpError);
+                                        if (tmpError != Error::NONE) {
+                                            return;
+                                        }
+
+                                        // import buffers
+                                        for (uint32_t i = 0; i < bufferCount; i++) {
+                                            error = mMapper.importBuffer(tmpBuffers[i],
+                                                                         &outBufferHandles[i]);
+                                            if (error != NO_ERROR) {
+                                                for (uint32_t j = 0; j < i; j++) {
+                                                    mMapper.freeBuffer(outBufferHandles[j]);
+                                                    outBufferHandles[j] = nullptr;
+                                                }
+                                                return;
+                                            }
+                                        }
+                                        *outStride = tmpStride;
+                                    });
+
+    // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+    hardware::IPCThreadState::self()->flushCommands();
+
+    return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 7670ac6..3fc6a2d 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "GraphicBuffer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <ui/GraphicBuffer.h>
 
@@ -22,10 +23,14 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
-#include <ui/DetachedBufferHandle.h>
+#ifndef LIBUI_IN_VNDK
+#include <ui/BufferHubBuffer.h>
+#endif // LIBUI_IN_VNDK
+
 #include <ui/Gralloc2.h>
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
+#include <utils/Trace.h>
 
 namespace android {
 
@@ -44,6 +49,22 @@
     return static_cast<GraphicBuffer *>(anwb);
 }
 
+GraphicBuffer* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer* buffer) {
+    return reinterpret_cast<GraphicBuffer*>(buffer);
+}
+
+GraphicBuffer const* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer const* buffer) {
+    return reinterpret_cast<GraphicBuffer const*>(buffer);
+}
+
+AHardwareBuffer* GraphicBuffer::toAHardwareBuffer() {
+    return reinterpret_cast<AHardwareBuffer*>(this);
+}
+
+AHardwareBuffer const* GraphicBuffer::toAHardwareBuffer() const {
+    return reinterpret_cast<AHardwareBuffer const*>(this);
+}
+
 GraphicBuffer::GraphicBuffer()
     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
@@ -55,7 +76,7 @@
     usage_deprecated = 0;
     usage  = 0;
     layerCount = 0;
-    handle = NULL;
+    handle = nullptr;
 }
 
 // deprecated
@@ -65,12 +86,11 @@
 {
 }
 
-GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
-    : GraphicBuffer()
-{
-    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
-            usage, std::move(requestorName));
+GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                             uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
+      : GraphicBuffer() {
+    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+                              std::move(requestorName));
 }
 
 // deprecated
@@ -83,22 +103,39 @@
 {
 }
 
-GraphicBuffer::GraphicBuffer(const native_handle_t* handle,
-        HandleWrapMethod method, uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t layerCount,
-        uint64_t usage,
-        uint32_t stride)
-    : GraphicBuffer()
-{
-    mInitCheck = initWithHandle(handle, method, width, height, format,
-            layerCount, usage, stride);
+GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method,
+                             uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                             uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride)
+      : GraphicBuffer() {
+    mInitCheck = initWithHandle(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+                                inUsage, inStride);
 }
 
+#ifndef LIBUI_IN_VNDK
+GraphicBuffer::GraphicBuffer(std::unique_ptr<BufferHubBuffer> buffer) : GraphicBuffer() {
+    if (buffer == nullptr) {
+        mInitCheck = BAD_VALUE;
+        return;
+    }
+
+    mInitCheck = initWithHandle(buffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
+                                buffer->desc().width, buffer->desc().height,
+                                static_cast<PixelFormat>(buffer->desc().format),
+                                buffer->desc().layers, buffer->desc().usage, buffer->desc().stride);
+    mBufferId = buffer->id();
+    mBufferHubBuffer = std::move(buffer);
+}
+#endif // LIBUI_IN_VNDK
+
 GraphicBuffer::~GraphicBuffer()
 {
+    ATRACE_CALL();
     if (handle) {
         free_handle();
     }
+    for (auto& [callback, context] : mDeathCallbacks) {
+        callback(context, mId);
+    }
 }
 
 void GraphicBuffer::free_handle()
@@ -109,7 +146,7 @@
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
     }
-    handle = NULL;
+    handle = nullptr;
 }
 
 status_t GraphicBuffer::initCheck() const {
@@ -123,7 +160,6 @@
 
 ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
 {
-    LOG_ALWAYS_FATAL_IF(this == NULL, "getNativeBuffer() called on NULL GraphicBuffer");
     return static_cast<ANativeWindowBuffer*>(
             const_cast<GraphicBuffer*>(this));
 }
@@ -145,7 +181,7 @@
     if (handle) {
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
-        handle = 0;
+        handle = nullptr;
     }
     return initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, "[Reallocation]");
 }
@@ -158,6 +194,7 @@
     if (inFormat != format) return true;
     if (inLayerCount != layerCount) return true;
     if ((usage & inUsage) != inUsage) return true;
+    if ((usage & USAGE_PROTECTED) != (inUsage & USAGE_PROTECTED)) return true;
     return false;
 }
 
@@ -184,26 +221,24 @@
     return err;
 }
 
-status_t GraphicBuffer::initWithHandle(const native_handle_t* handle,
-        HandleWrapMethod method, uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t layerCount, uint64_t usage,
-        uint32_t stride)
-{
-    ANativeWindowBuffer::width  = static_cast<int>(width);
-    ANativeWindowBuffer::height = static_cast<int>(height);
-    ANativeWindowBuffer::stride = static_cast<int>(stride);
-    ANativeWindowBuffer::format = format;
-    ANativeWindowBuffer::usage  = usage;
-    ANativeWindowBuffer::usage_deprecated = int(usage);
+status_t GraphicBuffer::initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+                                       uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                                       uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride) {
+    ANativeWindowBuffer::width = static_cast<int>(inWidth);
+    ANativeWindowBuffer::height = static_cast<int>(inHeight);
+    ANativeWindowBuffer::stride = static_cast<int>(inStride);
+    ANativeWindowBuffer::format = inFormat;
+    ANativeWindowBuffer::usage = inUsage;
+    ANativeWindowBuffer::usage_deprecated = int(inUsage);
 
-    ANativeWindowBuffer::layerCount = layerCount;
+    ANativeWindowBuffer::layerCount = inLayerCount;
 
     mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle;
 
     if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, width, height,
-                layerCount, format, usage, stride, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(inHandle, inWidth, inHeight, inLayerCount,
+                                                  inFormat, inUsage, inStride, &importedHandle);
         if (err != NO_ERROR) {
             initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
 
@@ -211,28 +246,28 @@
         }
 
         if (method == TAKE_UNREGISTERED_HANDLE) {
-            native_handle_close(handle);
-            native_handle_delete(const_cast<native_handle_t*>(handle));
+            native_handle_close(inHandle);
+            native_handle_delete(const_cast<native_handle_t*>(inHandle));
         }
 
-        handle = importedHandle;
-        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+        inHandle = importedHandle;
+        mBufferMapper.getTransportSize(inHandle, &mTransportNumFds, &mTransportNumInts);
     }
 
-    ANativeWindowBuffer::handle = handle;
+    ANativeWindowBuffer::handle = inHandle;
 
     return NO_ERROR;
 }
 
-status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr)
-{
+status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr, int32_t* outBytesPerPixel,
+                             int32_t* outBytesPerStride) {
     const Rect lockBounds(width, height);
-    status_t res = lock(inUsage, lockBounds, vaddr);
+    status_t res = lock(inUsage, lockBounds, vaddr, outBytesPerPixel, outBytesPerStride);
     return res;
 }
 
-status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr)
-{
+status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr,
+                             int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
     if (rect.left < 0 || rect.right  > width ||
         rect.top  < 0 || rect.bottom > height) {
         ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -240,7 +275,10 @@
                 width, height);
         return BAD_VALUE;
     }
-    status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr);
+
+    status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr, outBytesPerPixel,
+                                          outBytesPerStride);
+
     return res;
 }
 
@@ -271,22 +309,22 @@
     return res;
 }
 
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+                                  int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
     const Rect lockBounds(width, height);
-    status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd);
+    status_t res =
+            lockAsync(inUsage, lockBounds, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
     return res;
 }
 
-status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
-        void** vaddr, int fenceFd)
-{
-    return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd);
+status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+                                  int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+    return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
 }
 
-status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage,
-        uint64_t inConsumerUsage, const Rect& rect, void** vaddr, int fenceFd)
-{
+status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
+                                  const Rect& rect, void** vaddr, int fenceFd,
+                                  int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
     if (rect.left < 0 || rect.right  > width ||
         rect.top  < 0 || rect.bottom > height) {
         ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -294,8 +332,10 @@
                 width, height);
         return BAD_VALUE;
     }
-    status_t res = getBufferMapper().lockAsync(handle, inProducerUsage,
-            inConsumerUsage, rect, vaddr, fenceFd);
+
+    status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
+                                               vaddr, fenceFd, outBytesPerPixel, outBytesPerStride);
+
     return res;
 }
 
@@ -327,15 +367,37 @@
     return res;
 }
 
+status_t GraphicBuffer::isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                                    uint32_t inLayerCount, uint64_t inUsage,
+                                    bool* outSupported) const {
+    return mBufferMapper.isSupported(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+                                     outSupported);
+}
+
 size_t GraphicBuffer::getFlattenedSize() const {
+#ifndef LIBUI_IN_VNDK
+    if (mBufferHubBuffer != nullptr) {
+        return 48;
+    }
+#endif
     return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
+#ifndef LIBUI_IN_VNDK
+    if (mBufferHubBuffer != nullptr) {
+        return 0;
+    }
+#endif
     return static_cast<size_t>(handle ? mTransportNumFds : 0);
 }
 
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
+#ifndef LIBUI_IN_VNDK
+    if (mBufferHubBuffer != nullptr) {
+        return flattenBufferHubBuffer(buffer, size);
+    }
+#endif
     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
     if (size < sizeNeeded) return NO_MEMORY;
 
@@ -362,7 +424,7 @@
         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>(mTransportNumInts) * sizeof(int));
+               static_cast<size_t>(mTransportNumInts) * sizeof(int));
     }
 
     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
@@ -371,14 +433,13 @@
         fds += mTransportNumFds;
         count -= static_cast<size_t>(mTransportNumFds);
     }
-
     return NO_ERROR;
 }
 
-status_t GraphicBuffer::unflatten(
-        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
-    if (size < 12 * sizeof(int)) {
-        android_errorWriteLog(0x534e4554, "114223584");
+status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
+                                  size_t& count) {
+    // Check if size is not smaller than buf[0] is supposed to take.
+    if (size < sizeof(int)) {
         return NO_MEMORY;
     }
 
@@ -393,10 +454,21 @@
     } else if (buf[0] == 'GBFR') {
         // old version, when usage bits were 32-bits
         flattenWordCount = 12;
+    } else if (buf[0] == 'BHBB') { // BufferHub backed buffer.
+#ifndef LIBUI_IN_VNDK
+        return unflattenBufferHubBuffer(buffer, size);
+#else
+        return BAD_TYPE;
+#endif
     } else {
         return BAD_TYPE;
     }
 
+    if (size < 12 * sizeof(int)) {
+        android_errorWriteLog(0x534e4554, "114223584");
+        return NO_MEMORY;
+    }
+
     const size_t numFds  = static_cast<size_t>(buf[10]);
     const size_t numInts = static_cast<size_t>(buf[11]);
 
@@ -409,7 +481,7 @@
         width = height = stride = format = usage_deprecated = 0;
         layerCount = 0;
         usage = 0;
-        handle = NULL;
+        handle = nullptr;
         ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts);
         return BAD_VALUE;
     }
@@ -437,13 +509,13 @@
         } else {
             usage = uint64_t(usage_deprecated);
         }
-        native_handle* h = native_handle_create(
-                static_cast<int>(numFds), static_cast<int>(numInts));
+        native_handle* h =
+                native_handle_create(static_cast<int>(numFds), static_cast<int>(numInts));
         if (!h) {
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
             usage = 0;
-            handle = NULL;
+            handle = nullptr;
             ALOGE("unflatten: native_handle_create failed");
             return NO_MEMORY;
         }
@@ -454,7 +526,7 @@
         width = height = stride = format = usage_deprecated = 0;
         layerCount = 0;
         usage = 0;
-        handle = NULL;
+        handle = nullptr;
     }
 
     mId = static_cast<uint64_t>(buf[7]) << 32;
@@ -464,7 +536,7 @@
 
     mOwner = ownHandle;
 
-    if (handle != 0) {
+    if (handle != nullptr) {
         buffer_handle_t importedHandle;
         status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
                 uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
@@ -472,7 +544,7 @@
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
             usage = 0;
-            handle = NULL;
+            handle = nullptr;
             ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
             return err;
         }
@@ -487,28 +559,83 @@
     size -= sizeNeeded;
     fds += numFds;
     count -= numFds;
-
     return NO_ERROR;
 }
 
-bool GraphicBuffer::isDetachedBuffer() const {
-    return mDetachedBufferHandle && mDetachedBufferHandle->isValid();
+void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context) {
+    mDeathCallbacks.emplace_back(deathCallback, context);
 }
 
-status_t GraphicBuffer::setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> channel) {
-    if (isDetachedBuffer()) {
-        ALOGW("setDetachedBuffer: there is already a BufferHub channel associated with this "
-              "GraphicBuffer. Replacing the old one.");
+#ifndef LIBUI_IN_VNDK
+status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size) const {
+    sp<NativeHandle> tokenHandle = mBufferHubBuffer->duplicate();
+    if (tokenHandle == nullptr || tokenHandle->handle() == nullptr ||
+        tokenHandle->handle()->numFds != 0) {
+        return BAD_VALUE;
     }
 
-    mDetachedBufferHandle = std::move(channel);
+    // Size needed for one label, one number of ints inside the token, one generation number and
+    // the token itself.
+    int numIntsInToken = tokenHandle->handle()->numInts;
+    const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
+    if (size < sizeNeeded) {
+        ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
+              static_cast<int>(sizeNeeded), static_cast<int>(size));
+        return NO_MEMORY;
+    }
+    size -= sizeNeeded;
+
+    int* buf = static_cast<int*>(buffer);
+    buf[0] = 'BHBB';
+    buf[1] = numIntsInToken;
+    memcpy(buf + 2, tokenHandle->handle()->data, static_cast<size_t>(numIntsInToken) * sizeof(int));
+    buf[2 + numIntsInToken] = static_cast<int32_t>(mGenerationNumber);
+
     return NO_ERROR;
 }
 
-std::unique_ptr<DetachedBufferHandle> GraphicBuffer::takeDetachedBufferHandle() {
-    return std::move(mDetachedBufferHandle);
+status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size) {
+    const int* buf = static_cast<const int*>(buffer);
+    int numIntsInToken = buf[1];
+    // Size needed for one label, one number of ints inside the token, one generation number and
+    // the token itself.
+    const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
+    if (size < sizeNeeded) {
+        ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
+              static_cast<int>(sizeNeeded), static_cast<int>(size));
+        return NO_MEMORY;
+    }
+    size -= sizeNeeded;
+    native_handle_t* importToken = native_handle_create(/*numFds=*/0, /*numInts=*/numIntsInToken);
+    memcpy(importToken->data, buf + 2, static_cast<size_t>(buf[1]) * sizeof(int));
+    sp<NativeHandle> importTokenHandle = NativeHandle::create(importToken, /*ownHandle=*/true);
+    std::unique_ptr<BufferHubBuffer> bufferHubBuffer = BufferHubBuffer::import(importTokenHandle);
+    if (bufferHubBuffer == nullptr || bufferHubBuffer.get() == nullptr) {
+        return BAD_VALUE;
+    }
+    // Reconstruct this GraphicBuffer object using the new BufferHubBuffer object.
+    if (handle) {
+        free_handle();
+    }
+    mId = 0;
+    mGenerationNumber = static_cast<uint32_t>(buf[2 + numIntsInToken]);
+    mInitCheck =
+            initWithHandle(bufferHubBuffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
+                           bufferHubBuffer->desc().width, bufferHubBuffer->desc().height,
+                           static_cast<PixelFormat>(bufferHubBuffer->desc().format),
+                           bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage,
+                           bufferHubBuffer->desc().stride);
+    mBufferId = bufferHubBuffer->id();
+    mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));
+
+    return NO_ERROR;
 }
 
+bool GraphicBuffer::isBufferHubBuffer() const {
+    return mBufferHubBuffer != nullptr;
+}
+#endif // LIBUI_IN_VNDK
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index eaba1ed..0861a1f 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -24,72 +24,82 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <utils/Singleton.h>
-#include <utils/String8.h>
 #include <utils/Trace.h>
 
+#include <ui/Gralloc.h>
 #include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
 #include <ui/GraphicBufferMapper.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
+using base::StringAppendF;
+
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator )
 
 Mutex GraphicBufferAllocator::sLock;
 KeyedVector<buffer_handle_t,
     GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
 
-GraphicBufferAllocator::GraphicBufferAllocator()
-  : mMapper(GraphicBufferMapper::getInstance()),
-    mAllocator(std::make_unique<Gralloc2::Allocator>(
-                mMapper.getGrallocMapper()))
-{
+GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
+    mAllocator = std::make_unique<const Gralloc3Allocator>(
+            reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
+    if (!mAllocator->isLoaded()) {
+        mAllocator = std::make_unique<const Gralloc2Allocator>(
+                reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+    }
+
+    if (!mAllocator->isLoaded()) {
+        LOG_ALWAYS_FATAL("gralloc-allocator is missing");
+    }
 }
 
 GraphicBufferAllocator::~GraphicBufferAllocator() {}
 
-void GraphicBufferAllocator::dump(String8& result) const
-{
+size_t GraphicBufferAllocator::getTotalSize() const {
+    Mutex::Autolock _l(sLock);
+    size_t total = 0;
+    for (size_t i = 0; i < sAllocList.size(); ++i) {
+        total += sAllocList.valueAt(i).size;
+    }
+    return total;
+}
+
+void GraphicBufferAllocator::dump(std::string& result) const {
     Mutex::Autolock _l(sLock);
     KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
     size_t total = 0;
-    const size_t SIZE = 4096;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "Allocated buffers:\n");
-    result.append(buffer);
+    result.append("Allocated buffers:\n");
     const size_t c = list.size();
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
         if (rec.size) {
-            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
-                    " | %s\n",
-                    list.keyAt(i), rec.size/1024.0,
-                    rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
-                    rec.usage, rec.requestorName.c_str());
+            StringAppendF(&result,
+                          "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
+                          list.keyAt(i), rec.size / 1024.0, rec.width, rec.stride, rec.height,
+                          rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str());
         } else {
-            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
-                    " | %s\n",
-                    list.keyAt(i),
-                    rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
-                    rec.usage, rec.requestorName.c_str());
+            StringAppendF(&result,
+                          "%10p: unknown     | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
+                          list.keyAt(i), rec.width, rec.stride, rec.height, rec.layerCount,
+                          rec.format, rec.usage, rec.requestorName.c_str());
         }
-        result.append(buffer);
         total += rec.size;
     }
-    snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0);
-    result.append(buffer);
+    StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", total / 1024.0);
 
-    std::string deviceDump = mAllocator->dumpDebugInfo();
-    result.append(deviceDump.c_str(), deviceDump.size());
+    result.append(mAllocator->dumpDebugInfo());
 }
 
 void GraphicBufferAllocator::dumpToSystemLog()
 {
-    String8 s;
+    std::string s;
     GraphicBufferAllocator::getInstance().dump(s);
-    ALOGD("%s", s.string());
+    ALOGD("%s", s.c_str());
 }
 
 status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
@@ -108,15 +118,12 @@
     if (layerCount < 1)
         layerCount = 1;
 
-    Gralloc2::IMapper::BufferDescriptorInfo info = {};
-    info.width = width;
-    info.height = height;
-    info.layerCount = layerCount;
-    info.format = static_cast<Gralloc2::PixelFormat>(format);
-    info.usage = usage;
+    // TODO(b/72323293, b/72703005): Remove these invalid bits from callers
+    usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
 
-    Gralloc2::Error error = mAllocator->allocate(info, stride, handle);
-    if (error == Gralloc2::Error::NONE) {
+    status_t error =
+            mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
+    if (error == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
         uint32_t bpp = bytesPerPixel(format);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 2d8e582..25b7247 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -32,7 +32,9 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include <ui/Gralloc.h>
 #include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
 #include <ui/GraphicBuffer.h>
 
 #include <system/graphics.h>
@@ -43,12 +45,22 @@
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
 
 void GraphicBufferMapper::preloadHal() {
-    Gralloc2::Mapper::preload();
+    Gralloc2Mapper::preload();
+    Gralloc3Mapper::preload();
 }
 
-GraphicBufferMapper::GraphicBufferMapper()
-  : mMapper(std::make_unique<const Gralloc2::Mapper>())
-{
+GraphicBufferMapper::GraphicBufferMapper() {
+    mMapper = std::make_unique<const Gralloc3Mapper>();
+    if (!mMapper->isLoaded()) {
+        mMapper = std::make_unique<const Gralloc2Mapper>();
+        mMapperVersion = Version::GRALLOC_2;
+    } else {
+        mMapperVersion = Version::GRALLOC_3;
+    }
+
+    if (!mMapper->isLoaded()) {
+        LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+    }
 }
 
 status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
@@ -59,22 +71,15 @@
     ATRACE_CALL();
 
     buffer_handle_t bufferHandle;
-    Gralloc2::Error error = mMapper->importBuffer(
-            hardware::hidl_handle(rawHandle), &bufferHandle);
-    if (error != Gralloc2::Error::NONE) {
+    status_t error = mMapper->importBuffer(hardware::hidl_handle(rawHandle), &bufferHandle);
+    if (error != NO_ERROR) {
         ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
-        return static_cast<status_t>(error);
+        return 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) {
+    error = mMapper->validateBufferSize(bufferHandle, width, height, format, layerCount, usage,
+                                        stride);
+    if (error != NO_ERROR) {
         ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
         freeBuffer(bufferHandle);
         return static_cast<status_t>(error);
@@ -100,19 +105,10 @@
     return NO_ERROR;
 }
 
-static inline Gralloc2::IMapper::Rect asGralloc2Rect(const Rect& rect) {
-    Gralloc2::IMapper::Rect outRect{};
-    outRect.left = rect.left;
-    outRect.top = rect.top;
-    outRect.width = rect.width();
-    outRect.height = rect.height();
-    return outRect;
-}
-
-status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
-        const Rect& bounds, void** vaddr)
-{
-    return lockAsync(handle, usage, bounds, vaddr, -1);
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+                                   void** vaddr, int32_t* outBytesPerPixel,
+                                   int32_t* outBytesPerStride) {
+    return lockAsync(handle, usage, bounds, vaddr, -1, outBytesPerPixel, outBytesPerStride);
 }
 
 status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
@@ -132,27 +128,23 @@
     return error;
 }
 
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
-        uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
-{
-    return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd);
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+                                        void** vaddr, int fenceFd, int32_t* outBytesPerPixel,
+                                        int32_t* outBytesPerStride) {
+    return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd, outBytesPerPixel,
+                     outBytesPerStride);
 }
 
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
-        uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
-        void** vaddr, int fenceFd)
-{
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
+                                        uint64_t consumerUsage, const Rect& bounds, void** vaddr,
+                                        int fenceFd, int32_t* outBytesPerPixel,
+                                        int32_t* outBytesPerStride) {
     ATRACE_CALL();
 
     const uint64_t usage = static_cast<uint64_t>(
             android_convertGralloc1To0Usage(producerUsage, consumerUsage));
-    Gralloc2::Error error = mMapper->lock(handle, usage,
-            asGralloc2Rect(bounds), fenceFd, vaddr);
-
-    ALOGW_IF(error != Gralloc2::Error::NONE, "lock(%p, ...) failed: %d",
-            handle, error);
-
-    return static_cast<status_t>(error);
+    return mMapper->lock(handle, usage, bounds, fenceFd, vaddr, outBytesPerPixel,
+                         outBytesPerStride);
 }
 
 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
@@ -160,19 +152,7 @@
 {
     ATRACE_CALL();
 
-    Gralloc2::YCbCrLayout layout;
-    Gralloc2::Error error = mMapper->lock(handle, usage,
-            asGralloc2Rect(bounds), fenceFd, &layout);
-    if (error == Gralloc2::Error::NONE) {
-        ycbcr->y = layout.y;
-        ycbcr->cb = layout.cb;
-        ycbcr->cr = layout.cr;
-        ycbcr->ystride = static_cast<size_t>(layout.yStride);
-        ycbcr->cstride = static_cast<size_t>(layout.cStride);
-        ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
-    }
-
-    return static_cast<status_t>(error);
+    return mMapper->lock(handle, usage, bounds, fenceFd, ycbcr);
 }
 
 status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
@@ -184,5 +164,10 @@
     return NO_ERROR;
 }
 
+status_t GraphicBufferMapper::isSupported(uint32_t width, uint32_t height,
+                                          android::PixelFormat format, uint32_t layerCount,
+                                          uint64_t usage, bool* outSupported) {
+    return mMapper->isSupported(width, height, format, layerCount, usage, outSupported);
+}
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index a36911d..a5b3e89 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -24,8 +24,8 @@
 #endif
 
 HdrCapabilities::~HdrCapabilities() = default;
-HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
-HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
+HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default;
+HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default;
 
 size_t HdrCapabilities::getFlattenedSize() const {
     return  sizeof(mMaxLuminance) +
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
new file mode 100644
index 0000000..97ead21
--- /dev/null
+++ b/libs/ui/OWNERS
@@ -0,0 +1,7 @@
+lpy@google.com
+marissaw@google.com
+mathias@google.com
+romainguy@google.com
+stoza@google.com
+jwcai@google.com
+tianyuj@google.com
diff --git a/libs/ui/PublicFormat.cpp b/libs/ui/PublicFormat.cpp
new file mode 100644
index 0000000..70e3ce7
--- /dev/null
+++ b/libs/ui/PublicFormat.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/GraphicTypes.h> // ui::Dataspace
+#include <ui/PublicFormat.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+using ui::Dataspace;
+
+int mapPublicFormatToHalFormat(PublicFormat f) {
+    switch (f) {
+        case PublicFormat::JPEG:
+        case PublicFormat::DEPTH_POINT_CLOUD:
+        case PublicFormat::DEPTH_JPEG:
+        case PublicFormat::HEIC:
+            return HAL_PIXEL_FORMAT_BLOB;
+        case PublicFormat::DEPTH16:
+            return HAL_PIXEL_FORMAT_Y16;
+        case PublicFormat::RAW_SENSOR:
+        case PublicFormat::RAW_DEPTH:
+            return HAL_PIXEL_FORMAT_RAW16;
+        default:
+            // Most formats map 1:1
+            return static_cast<int>(f);
+    }
+}
+
+android_dataspace mapPublicFormatToHalDataspace(PublicFormat f) {
+    Dataspace dataspace;
+    switch (f) {
+        case PublicFormat::JPEG:
+            dataspace = Dataspace::V0_JFIF;
+            break;
+        case PublicFormat::DEPTH_POINT_CLOUD:
+        case PublicFormat::DEPTH16:
+        case PublicFormat::RAW_DEPTH:
+            dataspace = Dataspace::DEPTH;
+            break;
+        case PublicFormat::RAW_SENSOR:
+        case PublicFormat::RAW_PRIVATE:
+        case PublicFormat::RAW10:
+        case PublicFormat::RAW12:
+            dataspace = Dataspace::ARBITRARY;
+            break;
+        case PublicFormat::YUV_420_888:
+        case PublicFormat::NV21:
+        case PublicFormat::YV12:
+            dataspace = Dataspace::V0_JFIF;
+            break;
+        case PublicFormat::DEPTH_JPEG:
+            dataspace = Dataspace::DYNAMIC_DEPTH;
+            break;
+        case PublicFormat::HEIC:
+            dataspace = Dataspace::HEIF;
+            break;
+        default:
+            // Most formats map to UNKNOWN
+            dataspace = Dataspace::UNKNOWN;
+            break;
+    }
+    return static_cast<android_dataspace>(dataspace);
+}
+
+PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace) {
+    Dataspace ds = static_cast<Dataspace>(dataSpace);
+    switch (format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
+        case HAL_PIXEL_FORMAT_RGB_888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+        case HAL_PIXEL_FORMAT_Y8:
+        case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_RAW12:
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+        case HAL_PIXEL_FORMAT_YV12:
+            // Enums overlap in both name and value
+            return static_cast<PublicFormat>(format);
+        case HAL_PIXEL_FORMAT_RAW16:
+            switch (ds) {
+                case Dataspace::DEPTH:
+                    return PublicFormat::RAW_DEPTH;
+                default:
+                    return PublicFormat::RAW_SENSOR;
+            }
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Name differs, though value is the same
+            return PublicFormat::RAW_PRIVATE;
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+            // Name differs, though the value is the same
+            return PublicFormat::NV16;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            // Name differs, though the value is the same
+            return PublicFormat::NV21;
+        case HAL_PIXEL_FORMAT_YCbCr_422_I:
+            // Name differs, though the value is the same
+            return PublicFormat::YUY2;
+        case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+            // Name differs, though the value is the same
+            return PublicFormat::PRIVATE;
+        case HAL_PIXEL_FORMAT_Y16:
+            // Dataspace-dependent
+            switch (ds) {
+                case Dataspace::DEPTH:
+                    return PublicFormat::DEPTH16;
+                default:
+                    // Assume non-depth Y16 is just Y16.
+                    return PublicFormat::Y16;
+            }
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Dataspace-dependent
+            switch (ds) {
+                case Dataspace::DEPTH:
+                    return PublicFormat::DEPTH_POINT_CLOUD;
+                case Dataspace::V0_JFIF:
+                    return PublicFormat::JPEG;
+                case Dataspace::HEIF:
+                    return PublicFormat::HEIC;
+                default:
+                    if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_DYNAMIC_DEPTH)) {
+                        return PublicFormat::DEPTH_JPEG;
+                    } else {
+                        // Assume otherwise-marked blobs are also JPEG
+                        return PublicFormat::JPEG;
+                    }
+            }
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+            // Not defined in public API
+            return PublicFormat::UNKNOWN;
+
+        default:
+            return PublicFormat::UNKNOWN;
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index d8702e5..13fed3a 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -72,6 +72,14 @@
     return *this;
 }
 
+Rect& Rect::inset(int32_t _left, int32_t _top, int32_t _right, int32_t _bottom) {
+    this->left += _left;
+    this->top += _top;
+    this->right -= _right;
+    this->bottom -= _bottom;
+    return *this;
+}
+
 const Rect Rect::operator +(const Point& rhs) const {
     const Rect result(left + rhs.x, top + rhs.y, right + rhs.x, bottom + rhs.y);
     return result;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index fe4ae6c..55e3b99 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -19,9 +19,9 @@
 #include <inttypes.h>
 #include <limits.h>
 
+#include <android-base/stringprintf.h>
+
 #include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/CallStack.h>
 
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -30,10 +30,18 @@
 #include <private/ui/RegionHelper.h>
 
 // ----------------------------------------------------------------------------
-#define VALIDATE_REGIONS        (false)
+
+// ### VALIDATE_REGIONS ###
+// To enable VALIDATE_REGIONS traces, use the "libui-validate-regions-defaults"
+// in Android.bp. Do not #define VALIDATE_REGIONS here as it requires extra libs.
+
 #define VALIDATE_WITH_CORECG    (false)
 // ----------------------------------------------------------------------------
 
+#if defined(VALIDATE_REGIONS)
+#include <utils/CallStack.h>
+#endif
+
 #if VALIDATE_WITH_CORECG
 #include <core/SkRegion.h>
 #endif
@@ -41,6 +49,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+using base::StringAppendF;
+
 enum {
     op_nand = region_operator<Rect>::op_nand,
     op_and  = region_operator<Rect>::op_and,
@@ -64,7 +74,7 @@
 Region::Region(const Region& rhs)
     : mStorage(rhs.mStorage)
 {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(rhs, "rhs copy-ctor");
 #endif
 }
@@ -200,7 +210,7 @@
             outputRegion.mStorage, direction_LTR);
     outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
 
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(outputRegion, "T-Junction free region");
 #endif
 
@@ -209,7 +219,7 @@
 
 Region& Region::operator = (const Region& rhs)
 {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
@@ -325,6 +335,20 @@
     return *this;
 }
 
+Region& Region::scaleSelf(float sx, float sy) {
+    size_t count = mStorage.size();
+    Rect* rects = mStorage.editArray();
+    while (count) {
+        rects->left = static_cast<int32_t>(rects->left * sx + 0.5f);
+        rects->right = static_cast<int32_t>(rects->right * sx + 0.5f);
+        rects->top = static_cast<int32_t>(rects->top * sy + 0.5f);
+        rects->bottom = static_cast<int32_t>(rects->bottom * sy + 0.5f);
+        rects++;
+        count--;
+    }
+    return *this;
+}
+
 // ----------------------------------------------------------------------------
 
 const Region Region::merge(const Rect& rhs) const {
@@ -582,10 +606,12 @@
         result = false;
         ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
     }
+#if defined(VALIDATE_REGIONS)
     if (result == false && !silent) {
         reg.dump(name);
         CallStack stack(LOG_TAG);
     }
+#endif
     return result;
 }
 
@@ -593,7 +619,7 @@
         const Region& lhs,
         const Region& rhs, int dx, int dy)
 {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(lhs, "boolean_operation (before): lhs");
     validate(rhs, "boolean_operation (before): rhs");
     validate(dst, "boolean_operation (before): dst");
@@ -613,7 +639,7 @@
         operation(r);
     }
 
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(lhs, "boolean_operation: lhs");
     validate(rhs, "boolean_operation: rhs");
     validate(dst, "boolean_operation: dst");
@@ -711,7 +737,7 @@
         return;
     }
 
-#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
+#if VALIDATE_WITH_CORECG || defined(VALIDATE_REGIONS)
     boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
 #else
     size_t lhs_count;
@@ -743,7 +769,7 @@
 void Region::translate(Region& reg, int dx, int dy)
 {
     if ((dx || dy) && !reg.isEmpty()) {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
         validate(reg, "translate (before)");
 #endif
         size_t count = reg.mStorage.size();
@@ -753,7 +779,7 @@
             rects++;
             count--;
         }
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
         validate(reg, "translate (after)");
 #endif
     }
@@ -772,7 +798,7 @@
 }
 
 status_t Region::flatten(void* buffer, size_t size) const {
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(*this, "Region::flatten");
 #endif
     if (size < getFlattenedSize()) {
@@ -803,7 +829,7 @@
     }
 
     if (numRects > (UINT32_MAX / sizeof(Rect))) {
-        android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0);
+        android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
         return NO_MEMORY;
     }
 
@@ -819,7 +845,7 @@
         result.mStorage.push_back(rect);
     }
 
-#if VALIDATE_REGIONS
+#if defined(VALIDATE_REGIONS)
     validate(result, "Region::unflatten");
 #endif
 
@@ -854,16 +880,14 @@
 
 // ----------------------------------------------------------------------------
 
-void Region::dump(String8& out, const char* what, uint32_t /* flags */) const
-{
+void Region::dump(std::string& out, const char* what, uint32_t /* flags */) const {
     const_iterator head = begin();
     const_iterator const tail = end();
 
-    out.appendFormat("  Region %s (this=%p, count=%" PRIdPTR ")\n",
-            what, this, tail - head);
+    StringAppendF(&out, "  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head);
     while (head != tail) {
-        out.appendFormat("    [%3d, %3d, %3d, %3d]\n", head->left, head->top,
-                head->right, head->bottom);
+        StringAppendF(&out, "    [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right,
+                      head->bottom);
         ++head;
     }
 }
diff --git a/libs/ui/Size.cpp b/libs/ui/Size.cpp
new file mode 100644
index 0000000..d2996d1
--- /dev/null
+++ b/libs/ui/Size.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/Size.h>
+
+namespace android::ui {
+
+const Size Size::INVALID{-1, -1};
+const Size Size::EMPTY{0, 0};
+
+} // namespace android::ui
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
new file mode 100644
index 0000000..28c3f7b
--- /dev/null
+++ b/libs/ui/Transform.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2007 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 <math.h>
+
+#include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace ui {
+
+Transform::Transform() {
+    reset();
+}
+
+Transform::Transform(const Transform&  other)
+    : mMatrix(other.mMatrix), mType(other.mType) {
+}
+
+Transform::Transform(uint32_t orientation) {
+    set(orientation, 0, 0);
+}
+
+Transform::~Transform() = default;
+
+static const float EPSILON = 0.0f;
+
+bool Transform::isZero(float f) {
+    return fabs(f) <= EPSILON;
+}
+
+bool Transform::absIsOne(float f) {
+    return isZero(fabs(f) - 1.0f);
+}
+
+Transform Transform::operator * (const Transform& rhs) const
+{
+    if (CC_LIKELY(mType == IDENTITY))
+        return rhs;
+
+    Transform r(*this);
+    if (rhs.mType == IDENTITY)
+        return r;
+
+    // TODO: we could use mType to optimize the matrix multiply
+    const mat33& A(mMatrix);
+    const mat33& B(rhs.mMatrix);
+          mat33& D(r.mMatrix);
+    for (size_t i = 0; i < 3; i++) {
+        const float v0 = A[0][i];
+        const float v1 = A[1][i];
+        const float v2 = A[2][i];
+        D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2];
+        D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2];
+        D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2];
+    }
+    r.mType |= rhs.mType;
+
+    // TODO: we could recompute this value from r and rhs
+    r.mType &= 0xFF;
+    r.mType |= UNKNOWN_TYPE;
+    return r;
+}
+
+Transform& Transform::operator=(const Transform& other) {
+    mMatrix = other.mMatrix;
+    mType = other.mType;
+    return *this;
+}
+
+const vec3& Transform::operator [] (size_t i) const {
+    return mMatrix[i];
+}
+
+float Transform::tx() const {
+    return mMatrix[2][0];
+}
+
+float Transform::ty() const {
+    return mMatrix[2][1];
+}
+
+float Transform::sx() const {
+    return mMatrix[0][0];
+}
+
+float Transform::sy() const {
+    return mMatrix[1][1];
+}
+
+void Transform::reset() {
+    mType = IDENTITY;
+    for(size_t i = 0; i < 3; i++) {
+        vec3& v(mMatrix[i]);
+        for (size_t j = 0; j < 3; j++)
+            v[j] = ((i == j) ? 1.0f : 0.0f);
+    }
+}
+
+void Transform::set(float tx, float ty)
+{
+    mMatrix[2][0] = tx;
+    mMatrix[2][1] = ty;
+    mMatrix[2][2] = 1.0f;
+
+    if (isZero(tx) && isZero(ty)) {
+        mType &= ~TRANSLATE;
+    } else {
+        mType |= TRANSLATE;
+    }
+}
+
+void Transform::set(float a, float b, float c, float d)
+{
+    mat33& M(mMatrix);
+    M[0][0] = a;    M[1][0] = b;
+    M[0][1] = c;    M[1][1] = d;
+    M[0][2] = 0;    M[1][2] = 0;
+    mType = UNKNOWN_TYPE;
+}
+
+status_t Transform::set(uint32_t flags, float w, float h)
+{
+    if (flags & ROT_INVALID) {
+        // that's not allowed!
+        reset();
+        return BAD_VALUE;
+    }
+
+    Transform H, V, R;
+    if (flags & ROT_90) {
+        // w & h are inverted when rotating by 90 degrees
+        std::swap(w, h);
+    }
+
+    if (flags & FLIP_H) {
+        H.mType = (FLIP_H << 8) | SCALE;
+        H.mType |= isZero(w) ? IDENTITY : TRANSLATE;
+        mat33& M(H.mMatrix);
+        M[0][0] = -1;
+        M[2][0] = w;
+    }
+
+    if (flags & FLIP_V) {
+        V.mType = (FLIP_V << 8) | SCALE;
+        V.mType |= isZero(h) ? IDENTITY : TRANSLATE;
+        mat33& M(V.mMatrix);
+        M[1][1] = -1;
+        M[2][1] = h;
+    }
+
+    if (flags & ROT_90) {
+        const float original_w = h;
+        R.mType = (ROT_90 << 8) | ROTATE;
+        R.mType |= isZero(original_w) ? IDENTITY : TRANSLATE;
+        mat33& M(R.mMatrix);
+        M[0][0] = 0;    M[1][0] =-1;    M[2][0] = original_w;
+        M[0][1] = 1;    M[1][1] = 0;
+    }
+
+    *this = (R*(H*V));
+    return NO_ERROR;
+}
+
+vec2 Transform::transform(const vec2& v) const {
+    vec2 r;
+    const mat33& M(mMatrix);
+    r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0];
+    r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1];
+    return r;
+}
+
+vec3 Transform::transform(const vec3& v) const {
+    vec3 r;
+    const mat33& M(mMatrix);
+    r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2];
+    r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2];
+    r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2];
+    return r;
+}
+
+vec2 Transform::transform(int x, int y) const
+{
+    return transform(vec2(x,y));
+}
+
+Rect Transform::makeBounds(int w, int h) const
+{
+    return transform( Rect(w, h) );
+}
+
+Rect Transform::transform(const Rect& bounds, bool roundOutwards) const
+{
+    Rect r;
+    vec2 lt( bounds.left,  bounds.top    );
+    vec2 rt( bounds.right, bounds.top    );
+    vec2 lb( bounds.left,  bounds.bottom );
+    vec2 rb( bounds.right, bounds.bottom );
+
+    lt = transform(lt);
+    rt = transform(rt);
+    lb = transform(lb);
+    rb = transform(rb);
+
+    if (roundOutwards) {
+        r.left   = static_cast<int32_t>(floorf(std::min({lt[0], rt[0], lb[0], rb[0]})));
+        r.top    = static_cast<int32_t>(floorf(std::min({lt[1], rt[1], lb[1], rb[1]})));
+        r.right  = static_cast<int32_t>(ceilf(std::max({lt[0], rt[0], lb[0], rb[0]})));
+        r.bottom = static_cast<int32_t>(ceilf(std::max({lt[1], rt[1], lb[1], rb[1]})));
+    } else {
+        r.left   = static_cast<int32_t>(floorf(std::min({lt[0], rt[0], lb[0], rb[0]}) + 0.5f));
+        r.top    = static_cast<int32_t>(floorf(std::min({lt[1], rt[1], lb[1], rb[1]}) + 0.5f));
+        r.right  = static_cast<int32_t>(floorf(std::max({lt[0], rt[0], lb[0], rb[0]}) + 0.5f));
+        r.bottom = static_cast<int32_t>(floorf(std::max({lt[1], rt[1], lb[1], rb[1]}) + 0.5f));
+    }
+
+    return r;
+}
+
+FloatRect Transform::transform(const FloatRect& bounds) const
+{
+    vec2 lt(bounds.left, bounds.top);
+    vec2 rt(bounds.right, bounds.top);
+    vec2 lb(bounds.left, bounds.bottom);
+    vec2 rb(bounds.right, bounds.bottom);
+
+    lt = transform(lt);
+    rt = transform(rt);
+    lb = transform(lb);
+    rb = transform(rb);
+
+    FloatRect r;
+    r.left = std::min({lt[0], rt[0], lb[0], rb[0]});
+    r.top = std::min({lt[1], rt[1], lb[1], rb[1]});
+    r.right = std::max({lt[0], rt[0], lb[0], rb[0]});
+    r.bottom = std::max({lt[1], rt[1], lb[1], rb[1]});
+
+    return r;
+}
+
+Region Transform::transform(const Region& reg) const
+{
+    Region out;
+    if (CC_UNLIKELY(type() > TRANSLATE)) {
+        if (CC_LIKELY(preserveRects())) {
+            Region::const_iterator it = reg.begin();
+            Region::const_iterator const end = reg.end();
+            while (it != end) {
+                out.orSelf(transform(*it++));
+            }
+        } else {
+            out.set(transform(reg.bounds()));
+        }
+    } else {
+        int xpos = static_cast<int>(floorf(tx() + 0.5f));
+        int ypos = static_cast<int>(floorf(ty() + 0.5f));
+        out = reg.translate(xpos, ypos);
+    }
+    return out;
+}
+
+uint32_t Transform::type() const
+{
+    if (mType & UNKNOWN_TYPE) {
+        // recompute what this transform is
+
+        const mat33& M(mMatrix);
+        const float a = M[0][0];
+        const float b = M[1][0];
+        const float c = M[0][1];
+        const float d = M[1][1];
+        const float x = M[2][0];
+        const float y = M[2][1];
+
+        bool scale = false;
+        uint32_t flags = ROT_0;
+        if (isZero(b) && isZero(c)) {
+            if (a<0)    flags |= FLIP_H;
+            if (d<0)    flags |= FLIP_V;
+            if (!absIsOne(a) || !absIsOne(d)) {
+                scale = true;
+            }
+        } else if (isZero(a) && isZero(d)) {
+            flags |= ROT_90;
+            if (b>0)    flags |= FLIP_V;
+            if (c<0)    flags |= FLIP_H;
+            if (!absIsOne(b) || !absIsOne(c)) {
+                scale = true;
+            }
+        } else {
+            // there is a skew component and/or a non 90 degrees rotation
+            flags = ROT_INVALID;
+        }
+
+        mType = flags << 8;
+        if (flags & ROT_INVALID) {
+            mType |= UNKNOWN;
+        } else {
+            if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180))
+                mType |= ROTATE;
+            if (flags & FLIP_H)
+                mType ^= SCALE;
+            if (flags & FLIP_V)
+                mType ^= SCALE;
+            if (scale)
+                mType |= SCALE;
+        }
+
+        if (!isZero(x) || !isZero(y))
+            mType |= TRANSLATE;
+    }
+    return mType;
+}
+
+Transform Transform::inverse() const {
+    // our 3x3 matrix is always of the form of a 2x2 transformation
+    // followed by a translation: T*M, therefore:
+    // (T*M)^-1 = M^-1 * T^-1
+    Transform result;
+    if (mType <= TRANSLATE) {
+        // 1 0 0
+        // 0 1 0
+        // x y 1
+        result = *this;
+        result.mMatrix[2][0] = -result.mMatrix[2][0];
+        result.mMatrix[2][1] = -result.mMatrix[2][1];
+    } else {
+        // a c 0
+        // b d 0
+        // x y 1
+        const mat33& M(mMatrix);
+        const float a = M[0][0];
+        const float b = M[1][0];
+        const float c = M[0][1];
+        const float d = M[1][1];
+        const float x = M[2][0];
+        const float y = M[2][1];
+
+        const float idet = 1.0f / (a*d - b*c);
+        result.mMatrix[0][0] =  d*idet;
+        result.mMatrix[0][1] = -c*idet;
+        result.mMatrix[1][0] = -b*idet;
+        result.mMatrix[1][1] =  a*idet;
+        result.mType = mType;
+
+        vec2 T(-x, -y);
+        T = result.transform(T);
+        result.mMatrix[2][0] = T[0];
+        result.mMatrix[2][1] = T[1];
+    }
+    return result;
+}
+
+uint32_t Transform::getType() const {
+    return type() & 0xFF;
+}
+
+uint32_t Transform::getOrientation() const
+{
+    return (type() >> 8) & 0xFF;
+}
+
+bool Transform::preserveRects() const
+{
+    return (getOrientation() & ROT_INVALID) ? false : true;
+}
+
+mat4 Transform::asMatrix4() const {
+    // Internally Transform uses a 3x3 matrix since the transform is meant for
+    // two-dimensional values. An equivalent 4x4 matrix means inserting an extra
+    // row and column which adds as an identity transform on the third
+    // dimension.
+
+    mat4 m = mat4{mat4::NO_INIT}; // NO_INIT since we explicitly set every element
+
+    m[0][0] = mMatrix[0][0];
+    m[0][1] = mMatrix[0][1];
+    m[0][2] = 0.f;
+    m[0][3] = mMatrix[0][2];
+
+    m[1][0] = mMatrix[1][0];
+    m[1][1] = mMatrix[1][1];
+    m[1][2] = 0.f;
+    m[1][3] = mMatrix[1][2];
+
+    m[2][0] = 0.f;
+    m[2][1] = 0.f;
+    m[2][2] = 1.f;
+    m[2][3] = 0.f;
+
+    m[3][0] = mMatrix[2][0];
+    m[3][1] = mMatrix[2][1];
+    m[3][2] = 0.f;
+    m[3][3] = mMatrix[2][2];
+
+    return m;
+}
+
+void Transform::dump(std::string& out, const char* name) const {
+    using android::base::StringAppendF;
+
+    type(); // Ensure the information in mType is up to date
+
+    const uint32_t type = mType;
+    const uint32_t orient = type >> 8;
+
+    StringAppendF(&out, "%s 0x%08x (", name, orient);
+
+    if (orient & ROT_INVALID) {
+        out.append("ROT_INVALID ");
+    } else {
+        if (orient & ROT_90) {
+            out.append("ROT_90 ");
+        } else {
+            out.append("ROT_0 ");
+        }
+        if (orient & FLIP_V) out.append("FLIP_V ");
+        if (orient & FLIP_H) out.append("FLIP_H ");
+    }
+
+    StringAppendF(&out, ") 0x%02x (", type);
+
+    if (!(type & (SCALE | ROTATE | TRANSLATE))) out.append("IDENTITY ");
+    if (type & SCALE) out.append("SCALE ");
+    if (type & ROTATE) out.append("ROTATE ");
+    if (type & TRANSLATE) out.append("TRANSLATE ");
+
+    out.append(")\n");
+
+    for (size_t i = 0; i < 3; i++) {
+        StringAppendF(&out, "    %.4f  %.4f  %.4f\n", static_cast<double>(mMatrix[0][i]),
+                      static_cast<double>(mMatrix[1][i]), static_cast<double>(mMatrix[2][i]));
+    }
+}
+
+void Transform::dump(const char* name) const {
+    std::string out;
+    dump(out, name);
+    ALOGD("%s", out.c_str());
+}
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/UiConfig.cpp b/libs/ui/UiConfig.cpp
index 7730690..0ac863d 100644
--- a/libs/ui/UiConfig.cpp
+++ b/libs/ui/UiConfig.cpp
@@ -18,8 +18,7 @@
 
 namespace android {
 
-void appendUiConfigString(String8& configStr)
-{
+void appendUiConfigString(std::string& configStr) {
     static const char* config =
             " [libui]";
     configStr.append(config);
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
new file mode 100644
index 0000000..5ba189c
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BUFFER_HUB_BUFFER_H_
+#define ANDROID_BUFFER_HUB_BUFFER_H_
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
+#include <ui/BufferHubDefs.h>
+#include <ui/BufferHubEventFd.h>
+#include <ui/BufferHubMetadata.h>
+#include <utils/NativeHandle.h>
+
+namespace android {
+
+class BufferHubBuffer {
+public:
+    // Allocates a standalone BufferHubBuffer.
+    static std::unique_ptr<BufferHubBuffer> create(uint32_t width, uint32_t height,
+                                                   uint32_t layerCount, uint32_t format,
+                                                   uint64_t usage, size_t userMetadataSize);
+
+    // Imports the given token to a BufferHubBuffer. Not taking ownership of the token.
+    static std::unique_ptr<BufferHubBuffer> import(const sp<NativeHandle>& token);
+
+    BufferHubBuffer(const BufferHubBuffer&) = delete;
+    void operator=(const BufferHubBuffer&) = delete;
+
+    virtual ~BufferHubBuffer();
+
+    // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
+    // BufferHub share the same buffer id.
+    int id() const { return mId; }
+
+    // Returns the buffer description, which is guaranteed to be faithful values from BufferHub.
+    const AHardwareBuffer_Desc& desc() const { return mBufferDesc; }
+
+    // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle
+    // after use.
+    native_handle_t* duplicateHandle() {
+        return native_handle_clone(mBufferHandle.getNativeHandle());
+    }
+
+    const BufferHubEventFd& eventFd() const { return mEventFd; }
+
+    // Returns the current value of MetadataHeader::bufferState.
+    uint32_t bufferState() const { return mBufferState->load(std::memory_order_acquire); }
+
+    // A state mask which is unique to a buffer hub client among all its siblings sharing the same
+    // concrete graphic buffer.
+    uint32_t clientStateMask() const { return mClientStateMask; }
+
+    size_t userMetadataSize() const { return mMetadata.userMetadataSize(); }
+
+    // Returns true if the BufferClient is still alive.
+    bool isConnected() const { return mBufferClient->ping().isOk(); }
+
+    // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask,
+    // valid metadata and valid buffer client
+    bool isValid() const;
+
+    // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
+    // gained.
+    // The buffer can be gained as long as there is no other client in acquired or gained state.
+    int gain();
+
+    // Posts the gained buffer for other buffer clients to use the buffer.
+    // The buffer can be posted iff the buffer state for this client is gained.
+    // After posting the buffer, this client is put to released state and does not have access to
+    // the buffer for this cycle of the usage of the buffer.
+    int post();
+
+    // Acquires the buffer for shared read permission.
+    // The buffer can be acquired iff the buffer state for this client is posted.
+    int acquire();
+
+    // Releases the buffer.
+    // The buffer can be released from any buffer state.
+    // After releasing the buffer, this client no longer have any permissions to the buffer for the
+    // current cycle of the usage of the buffer.
+    int release();
+
+    // Returns whether the buffer is released by all active clients or not.
+    bool isReleased() const;
+
+    // Creates a token that stands for this BufferHubBuffer client and could be used for Import to
+    // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
+    // gralloc buffer and ashmem region for metadata. Not taking ownership of the token.
+    // Returns a valid token on success, nullptr on failure.
+    sp<NativeHandle> duplicate();
+
+private:
+    BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
+                    uint64_t usage, size_t userMetadataSize);
+
+    BufferHubBuffer(const sp<NativeHandle>& token);
+
+    int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits);
+
+    // Global id for the buffer that is consistent across processes.
+    int mId = 0;
+
+    // Client state mask of this BufferHubBuffer object. It is unique amoung all
+    // clients/users of the buffer.
+    uint32_t mClientStateMask = 0U;
+
+    // Stores ground truth of the buffer.
+    AHardwareBuffer_Desc mBufferDesc;
+
+    // Wraps the gralloc buffer handle of this buffer.
+    hardware::hidl_handle mBufferHandle;
+
+    // Event fd used for signalling buffer state changes. Shared by all clients of the same buffer.
+    BufferHubEventFd mEventFd;
+
+    // An ashmem-based metadata object. The same shared memory are mapped to the
+    // bufferhubd daemon and all buffer clients.
+    BufferHubMetadata mMetadata;
+    // Shortcuts to the atomics inside the header of mMetadata.
+    std::atomic<uint32_t>* mBufferState = nullptr;
+    std::atomic<uint32_t>* mFenceState = nullptr;
+    std::atomic<uint32_t>* mActiveClientsBitMask = nullptr;
+
+    // HwBinder backend
+    sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient;
+};
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_BUFFER_H_
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
new file mode 100644
index 0000000..10f274f
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BUFFER_HUB_DEFS_H_
+#define ANDROID_BUFFER_HUB_DEFS_H_
+
+#include <atomic>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpacked"
+// TODO(b/118893702): remove dependency once DvrNativeBufferMetadata moved out of libdvr
+#include <dvr/dvr_api.h>
+#pragma clang diagnostic pop
+
+namespace android {
+
+namespace BufferHubDefs {
+
+// Single buffer clients (up to 16) ownership signal.
+// 32-bit atomic unsigned int.
+// Each client takes 2 bits. The first bit locates in the first 16 bits of
+// bufferState; the second bit locates in the last 16 bits of bufferState.
+// Client states:
+// Gained state 11. Exclusive write state.
+// Posted state 10.
+// Acquired state 01. Shared read state.
+// Released state 00.
+//
+//  MSB                        LSB
+//   |                          |
+//   v                          v
+// [C15|...|C1|C0|C15| ... |C1|C0]
+
+// Maximum number of clients a buffer can have.
+static constexpr int kMaxNumberOfClients = 16;
+
+// Definition of bit masks.
+//  MSB                            LSB
+//   | kHighBitsMask | kLowbitsMask |
+//   v               v              v
+// [b31|   ...   |b16|b15|   ...  |b0]
+
+// The location of lower 16 bits in the 32-bit buffer state.
+static constexpr uint32_t kLowbitsMask = (1U << kMaxNumberOfClients) - 1U;
+
+// The location of higher 16 bits in the 32-bit buffer state.
+static constexpr uint32_t kHighBitsMask = ~kLowbitsMask;
+
+// The client bit mask of the first client.
+static constexpr uint32_t kFirstClientBitMask = (1U << kMaxNumberOfClients) + 1U;
+
+// Returns true if any of the client is in gained state.
+static inline bool isAnyClientGained(uint32_t state) {
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    return highBits == lowBits && lowBits != 0U;
+}
+
+// Returns true if the input client is in gained state.
+static inline bool isClientGained(uint32_t state, uint32_t client_bit_mask) {
+    return state == client_bit_mask;
+}
+
+// Returns true if any of the client is in posted state.
+static inline bool isAnyClientPosted(uint32_t state) {
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    uint32_t postedOrAcquired = highBits ^ lowBits;
+    return postedOrAcquired & highBits;
+}
+
+// Returns true if the input client is in posted state.
+static inline bool isClientPosted(uint32_t state, uint32_t client_bit_mask) {
+    uint32_t clientBits = state & client_bit_mask;
+    if (clientBits == 0U) return false;
+    uint32_t lowBits = clientBits & kLowbitsMask;
+    return lowBits == 0U;
+}
+
+// Return true if any of the client is in acquired state.
+static inline bool isAnyClientAcquired(uint32_t state) {
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    uint32_t postedOrAcquired = highBits ^ lowBits;
+    return postedOrAcquired & lowBits;
+}
+
+// Return true if the input client is in acquired state.
+static inline bool isClientAcquired(uint32_t state, uint32_t client_bit_mask) {
+    uint32_t clientBits = state & client_bit_mask;
+    if (clientBits == 0U) return false;
+    uint32_t highBits = clientBits & kHighBitsMask;
+    return highBits == 0U;
+}
+
+// Returns true if the input client is in released state.
+static inline bool isClientReleased(uint32_t state, uint32_t client_bit_mask) {
+    return (state & client_bit_mask) == 0U;
+}
+
+// Returns the next available buffer client's client_state_masks.
+// @params union_bits. Union of all existing clients' client_state_masks.
+static inline uint32_t findNextAvailableClientStateMask(uint32_t union_bits) {
+    uint32_t lowUnion = union_bits & kLowbitsMask;
+    if (lowUnion == kLowbitsMask) return 0U;
+    uint32_t incremented = lowUnion + 1U;
+    uint32_t difference = incremented ^ lowUnion;
+    uint32_t newLowBit = (difference + 1U) >> 1;
+    return newLowBit + (newLowBit << kMaxNumberOfClients);
+}
+
+struct __attribute__((aligned(8))) MetadataHeader {
+    // Internal data format, which can be updated as long as the size, padding and field alignment
+    // of the struct is consistent within the same ABI. As this part is subject for future updates,
+    // it's not stable cross Android version, so don't have it visible from outside of the Android
+    // platform (include Apps and vendor HAL).
+
+    // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
+    // bufferState.
+    std::atomic<uint32_t> bufferState;
+
+    // Every client takes up one bit in fenceState. Only the lower 32 bits are valid. The upper 32
+    // bits are there for easier manipulation, but the value should be ignored.
+    std::atomic<uint32_t> fenceState;
+
+    // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
+    // activeClientsBitMask.
+    std::atomic<uint32_t> activeClientsBitMask;
+
+    // Explicit padding 4 bytes.
+    uint32_t padding;
+
+    // The index of the buffer queue where the buffer belongs to.
+    uint64_t queueIndex;
+
+    // Public data format, which should be updated with caution. See more details in dvr_api.h
+    DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+/**
+ * android.frameworks.bufferhub@1.0::BufferTraits.bufferInfo is an opaque handle. See
+ * https://cs.corp.google.com/android/frameworks/hardware/interfaces/bufferhub/1.0/types.hal for
+ * more details about android.frameworks.bufferhub@1.0::BufferTraits.
+ *
+ * This definition could be changed, but implementation of BufferHubService::buildBufferInfo
+ * (frameworks/native/services/bufferhub), VtsHalBufferHubV1_0TargetTest
+ * (frameworks/hardware/interfaces/bufferhub) and BufferHubBuffer::readBufferTraits (libui) will
+ * also need to be updated.
+ *
+ * It's definition should follow the following format:
+ * {
+ *   NumFds = 2,
+ *   NumInts = 3,
+ *   data[0] = Ashmem fd for BufferHubMetadata,
+ *   data[1] = event fd,
+ *   data[2] = buffer id,
+ *   data[3] = client state bit mask,
+ *   data[4] = user metadata size,
+ * }
+ */
+static constexpr int kBufferInfoNumFds = 2;
+static constexpr int kBufferInfoNumInts = 3;
+
+} // namespace BufferHubDefs
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_DEFS_H_
diff --git a/libs/ui/include/ui/BufferHubEventFd.h b/libs/ui/include/ui/BufferHubEventFd.h
new file mode 100644
index 0000000..8772304
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubEventFd.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BUFFER_HUB_EVENT_FD_H_
+#define ANDROID_BUFFER_HUB_EVENT_FD_H_
+
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class BufferHubEventFd {
+public:
+    /**
+     * Constructs a valid event fd.
+     */
+    BufferHubEventFd();
+
+    /**
+     * Constructs from a valid event fd. Caller is responsible for the validity of the fd. Takes
+     * ownership.
+     */
+    BufferHubEventFd(int fd);
+
+    /**
+     * Returns whether this BufferHubEventFd holds a valid event_fd.
+     */
+    bool isValid() const { return get() >= 0; }
+
+    /**
+     * Returns the fd number of the BufferHubEventFd object. Note that there is no ownership
+     * transfer.
+     */
+    int get() const { return mFd.get(); }
+
+    /**
+     * Signals the eventfd.
+     */
+    status_t signal() const;
+
+    /**
+     * Clears the signal from this eventfd if it is signaled.
+     */
+    status_t clear() const;
+
+private:
+    base::unique_fd mFd;
+};
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_EVENT_FD_H_
diff --git a/libs/ui/include/ui/BufferHubMetadata.h b/libs/ui/include/ui/BufferHubMetadata.h
new file mode 100644
index 0000000..3482507
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubMetadata.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BUFFER_HUB_METADATA_H_
+#define ANDROID_BUFFER_HUB_METADATA_H_
+
+#include <android-base/unique_fd.h>
+#include <ui/BufferHubDefs.h>
+
+namespace android {
+
+namespace {
+using base::unique_fd;
+} // namespace
+
+class BufferHubMetadata {
+public:
+    // Creates a new BufferHubMetadata backed by an ashmem region.
+    //
+    // @param userMetadataSize Size in bytes of the user defined metadata. The entire metadata
+    //        shared memory region to be allocated is the size of canonical
+    //        BufferHubDefs::MetadataHeader plus userMetadataSize.
+    static BufferHubMetadata create(size_t userMetadataSize);
+
+    // Imports an existing BufferHubMetadata from an ashmem FD.
+    //
+    // @param ashmemFd Ashmem file descriptor representing an ashmem region.
+    static BufferHubMetadata import(unique_fd ashmemFd);
+
+    BufferHubMetadata() = default;
+
+    BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); }
+
+    ~BufferHubMetadata();
+
+    BufferHubMetadata& operator=(BufferHubMetadata&& other) {
+        if (this != &other) {
+            mUserMetadataSize = other.mUserMetadataSize;
+            other.mUserMetadataSize = 0;
+
+            mAshmemFd = std::move(other.mAshmemFd);
+
+            // The old raw mMetadataHeader pointer must be cleared, otherwise the destructor will
+            // automatically mummap() the shared memory.
+            mMetadataHeader = other.mMetadataHeader;
+            other.mMetadataHeader = nullptr;
+        }
+        return *this;
+    }
+
+    // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem fd and the ashmem
+    // has been mapped into virtual address space.
+    bool isValid() const { return mAshmemFd.get() != -1 && mMetadataHeader != nullptr; }
+
+    size_t userMetadataSize() const { return mUserMetadataSize; }
+    size_t metadataSize() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; }
+
+    const unique_fd& ashmemFd() const { return mAshmemFd; }
+    BufferHubDefs::MetadataHeader* metadataHeader() { return mMetadataHeader; }
+
+private:
+    BufferHubMetadata(size_t userMetadataSize, unique_fd ashmemFd,
+                      BufferHubDefs::MetadataHeader* metadataHeader);
+
+    BufferHubMetadata(const BufferHubMetadata&) = delete;
+    void operator=(const BufferHubMetadata&) = delete;
+
+    size_t mUserMetadataSize = 0;
+    unique_fd mAshmemFd;
+    BufferHubDefs::MetadataHeader* mMetadataHeader = nullptr;
+};
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_METADATA_H_
diff --git a/libs/ui/include/ui/BufferQueueDefs.h b/libs/ui/include/ui/BufferQueueDefs.h
index 56de181..0fecda9 100644
--- a/libs/ui/include/ui/BufferQueueDefs.h
+++ b/libs/ui/include/ui/BufferQueueDefs.h
@@ -23,6 +23,16 @@
         // Attempts at runtime to increase the number of buffers past this
         // will fail.
         static constexpr int NUM_BUFFER_SLOTS = 64;
+
+        enum {
+            // A flag returned by dequeueBuffer when the client needs to call
+            // requestBuffer immediately thereafter.
+            BUFFER_NEEDS_REALLOCATION = 0x1,
+            // A flag returned by dequeueBuffer when all mirrored slots should be
+            // released by the client. This flag should always be processed first.
+            RELEASE_ALL_BUFFERS       = 0x2,
+        };
+
     } // namespace BufferQueueDefs
 } // namespace android
 
diff --git a/libs/ui/include/ui/ColorSpace.h b/libs/ui/include/ui/ColorSpace.h
index 8ccf6d3..241ec10 100644
--- a/libs/ui/include/ui/ColorSpace.h
+++ b/libs/ui/include/ui/ColorSpace.h
@@ -250,8 +250,8 @@
     // axis is thus already flipped
     // The source color space must define its values in the domain [0..1]
     // The generated LUT transforms from gamma space to gamma space
-    static std::unique_ptr<float3> createLUT(uint32_t size,
-            const ColorSpace& src, const ColorSpace& dst);
+    static std::unique_ptr<float3[]> createLUT(uint32_t size, const ColorSpace& src,
+                                               const ColorSpace& dst);
 
 private:
     static constexpr mat3 computeXYZMatrix(
diff --git a/libs/ui/include/ui/ConfigStoreTypes.h b/libs/ui/include/ui/ConfigStoreTypes.h
new file mode 100644
index 0000000..4445ae9
--- /dev/null
+++ b/libs/ui/include/ui/ConfigStoreTypes.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// android::ui::* in this header file will alias different types as
+// the HIDL interface is updated.
+namespace android {
+namespace ui {
+
+struct CieXyz {
+    float X;
+    float Y;
+    float Z;
+};
+struct DisplayPrimaries {
+    CieXyz red;
+    CieXyz green;
+    CieXyz blue;
+    CieXyz white;
+};
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/include/ui/DetachedBufferHandle.h b/libs/ui/include/ui/DetachedBufferHandle.h
deleted file mode 100644
index f3c328d..0000000
--- a/libs/ui/include/ui/DetachedBufferHandle.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-#define ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
-
-#include <pdx/channel_handle.h>
-
-#include <memory>
-
-namespace android {
-
-// A wrapper that holds a pdx::LocalChannelHandle object. From the handle, a BufferHub buffer can be
-// created. Current implementation assumes that the underlying transport is using libpdx (thus
-// holding a pdx::LocalChannelHandle object), but future implementation can change it to a Binder
-// backend if ever needed.
-class DetachedBufferHandle {
-public:
-    static std::unique_ptr<DetachedBufferHandle> Create(pdx::LocalChannelHandle handle) {
-        return std::unique_ptr<DetachedBufferHandle>(new DetachedBufferHandle(std::move(handle)));
-    }
-
-    // Accessors to get or take the internal pdx::LocalChannelHandle.
-    pdx::LocalChannelHandle& handle() { return mHandle; }
-    const pdx::LocalChannelHandle& handle() const { return mHandle; }
-
-    // Returns whether the DetachedBufferHandle holds a BufferHub channel.
-    bool isValid() const { return mHandle.valid(); }
-
-private:
-    // Constructs a DetachedBufferHandle from a pdx::LocalChannelHandle.
-    explicit DetachedBufferHandle(pdx::LocalChannelHandle handle) : mHandle(std::move(handle)) {}
-
-    pdx::LocalChannelHandle mHandle;
-};
-
-} // namespace android
-
-#endif // ANDROID_DETACHED_BUFFER_HUB_HANDLE_H
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 94caf6b..8976d2d 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -35,6 +35,8 @@
     bool secure{false};
     nsecs_t appVsyncOffset{0};
     nsecs_t presentationDeadline{0};
+    uint32_t viewportW{0};
+    uint32_t viewportH{0};
 };
 
 /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/libs/ui/include/ui/DisplayedFrameStats.h b/libs/ui/include/ui/DisplayedFrameStats.h
new file mode 100644
index 0000000..7a70ea1
--- /dev/null
+++ b/libs/ui/include/ui/DisplayedFrameStats.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+namespace android {
+
+struct DisplayedFrameStats {
+    /* The number of frames represented by this sample. */
+    uint64_t numFrames = 0;
+    /* A histogram counting how many times a pixel of a given value was displayed onscreen for
+     * FORMAT_COMPONENT_0. The buckets of the histogram are evenly weighted, the number of buckets
+     * is device specific. eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
+     * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
+     * were displayed onscreen in range 0x40->0x7F, etc.
+     */
+    std::vector<uint64_t> component_0_sample = {};
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_1. */
+    std::vector<uint64_t> component_1_sample = {};
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_2. */
+    std::vector<uint64_t> component_2_sample = {};
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_3. */
+    std::vector<uint64_t> component_3_sample = {};
+};
+
+} // namespace android
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index ec67fa9..6efecd3 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -99,6 +99,12 @@
     // be returned and errno will indicate the problem.
     int dup() const;
 
+    // Return the underlying file descriptor without giving up ownership. The
+    // returned file descriptor is only valid for as long as the owning Fence
+    // object lives. (If the situation is unclear, dup() is always a safer
+    // option.)
+    int get() const { return mFenceFd.get(); }
+
     // getSignalTime returns the system monotonic clock time at which the
     // fence transitioned to the signaled state.  If the fence is not signaled
     // then SIGNAL_TIME_PENDING is returned.  If the fence is invalid or if an
diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
index 871fcf2..ecba7f7 100644
--- a/libs/ui/include/ui/FenceTime.h
+++ b/libs/ui/include/ui/FenceTime.h
@@ -19,6 +19,7 @@
 
 #include <ui/Fence.h>
 #include <utils/Flattenable.h>
+#include <utils/Mutex.h>
 #include <utils/Timers.h>
 
 #include <atomic>
@@ -113,11 +114,6 @@
 
     void signalForTest(nsecs_t signalTime);
 
-    // Override new and delete since this needs 8-byte alignment, which
-    // is not guaranteed on x86.
-    static void* operator new(size_t nbytes) noexcept;
-    static void operator delete(void *p);
-
 private:
     // For tests only. If forceValidForTest is true, then getSignalTime will
     // never return SIGNAL_TIME_INVALID and isValid will always return true.
@@ -164,7 +160,7 @@
 
 private:
     mutable std::mutex mMutex;
-    std::queue<std::weak_ptr<FenceTime>> mQueue;
+    std::queue<std::weak_ptr<FenceTime>> mQueue GUARDED_BY(mMutex);
 };
 
 // Used by test code to create or get FenceTimes for a given Fence.
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 6a7479a..4cd9a0b 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -28,7 +28,7 @@
     float getHeight() const { return bottom - top; }
 
     FloatRect intersect(const FloatRect& other) const {
-        return {
+        FloatRect intersection = {
             // Inline to avoid tromping on other min/max defines or adding a
             // dependency on STL
             (left > other.left) ? left : other.left,
@@ -36,6 +36,10 @@
             (right < other.right) ? right : other.right,
             (bottom < other.bottom) ? bottom : other.bottom
         };
+        if (intersection.getWidth() < 0 || intersection.getHeight() < 0) {
+            return {0, 0, 0, 0};
+        }
+        return intersection;
     }
 
     float left = 0.0f;
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
new file mode 100644
index 0000000..6cc23f0
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC_H
+#define ANDROID_UI_GRALLOC_H
+
+#include <string>
+
+#include <hidl/HidlSupport.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// A wrapper to IMapper
+class GrallocMapper {
+public:
+    virtual ~GrallocMapper();
+
+    virtual bool isLoaded() const = 0;
+
+    virtual status_t createDescriptor(void* bufferDescriptorInfo,
+                                      void* outBufferDescriptor) const = 0;
+
+    // Import a buffer that is from another HAL, another process, or is
+    // cloned.
+    //
+    // The returned handle must be freed with freeBuffer.
+    virtual status_t importBuffer(const hardware::hidl_handle& rawHandle,
+                                  buffer_handle_t* outBufferHandle) const = 0;
+
+    virtual void freeBuffer(buffer_handle_t bufferHandle) const = 0;
+
+    virtual status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+                                        uint32_t height, android::PixelFormat format,
+                                        uint32_t layerCount, uint64_t usage,
+                                        uint32_t stride) const = 0;
+
+    virtual void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+                                  uint32_t* outNumInts) const = 0;
+
+    // The ownership of acquireFence is always transferred to the callee, even
+    // on errors.
+    virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                          int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                          int32_t* outBytesPerStride) const = 0;
+
+    // The ownership of acquireFence is always transferred to the callee, even
+    // on errors.
+    virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                          int acquireFence, android_ycbcr* ycbcr) const = 0;
+
+    // unlock returns a fence sync object (or -1) and the fence sync object is
+    // owned by the caller
+    virtual int unlock(buffer_handle_t bufferHandle) const = 0;
+
+    // isSupported queries whether or not a buffer with the given width, height,
+    // format, layer count, and usage can be allocated on the device.  If
+    // *outSupported is set to true, a buffer with the given specifications may be successfully
+    // allocated if resources are available.  If false, a buffer with the given specifications will
+    // never successfully allocate on this device. Note that this function is not guaranteed to be
+    // supported on all devices, in which case a status_t of INVALID_OPERATION will be returned.
+    virtual status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+                                 uint32_t layerCount, uint64_t usage, bool* outSupported) const = 0;
+};
+
+// A wrapper to IAllocator
+class GrallocAllocator {
+public:
+    virtual ~GrallocAllocator();
+
+    virtual bool isLoaded() const = 0;
+
+    virtual std::string dumpDebugInfo() const = 0;
+
+    /*
+     * The returned buffers are already imported and must not be imported
+     * again.  outBufferHandles must point to a space that can contain at
+     * least "bufferCount" buffer_handle_t.
+     */
+    virtual status_t allocate(uint32_t width, uint32_t height, PixelFormat format,
+                              uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+                              uint32_t* outStride, buffer_handle_t* outBufferHandles) const = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC_H
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 5a8dbda..948f597 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -23,119 +23,75 @@
 #include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
 
-namespace Gralloc2 {
-
-using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_1::BufferUsage;
-using hardware::graphics::common::V1_1::PixelFormat;
-using hardware::graphics::mapper::V2_1::IMapper;
-using hardware::graphics::mapper::V2_0::BufferDescriptor;
-using hardware::graphics::mapper::V2_0::Error;
-using hardware::graphics::mapper::V2_0::YCbCrLayout;
-
-// A wrapper to IMapper
-class Mapper {
+class Gralloc2Mapper : public GrallocMapper {
 public:
     static void preload();
 
-    Mapper();
+    Gralloc2Mapper();
 
-    Error createDescriptor(
-            const IMapper::BufferDescriptorInfo& descriptorInfo,
-            BufferDescriptor* outDescriptor) const;
+    bool isLoaded() const override;
 
-    // Import a buffer that is from another HAL, another process, or is
-    // cloned.
-    //
-    // The returned handle must be freed with freeBuffer.
-    Error importBuffer(const hardware::hidl_handle& rawHandle,
-            buffer_handle_t* outBufferHandle) const;
+    status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
 
-    void freeBuffer(buffer_handle_t bufferHandle) const;
+    status_t importBuffer(const hardware::hidl_handle& rawHandle,
+                          buffer_handle_t* outBufferHandle) const override;
 
-    Error validateBufferSize(buffer_handle_t bufferHandle,
-            const IMapper::BufferDescriptorInfo& descriptorInfo,
-            uint32_t stride) const;
+    void freeBuffer(buffer_handle_t bufferHandle) const override;
 
-    void getTransportSize(buffer_handle_t bufferHandle,
-            uint32_t* outNumFds, uint32_t* outNumInts) const;
+    status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+                                android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+                                uint32_t stride) const override;
 
-    // The ownership of acquireFence is always transferred to the callee, even
-    // on errors.
-    Error lock(buffer_handle_t bufferHandle, uint64_t usage,
-            const IMapper::Rect& accessRegion,
-            int acquireFence, void** outData) const;
+    void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+                          uint32_t* outNumInts) const override;
 
-    // The ownership of acquireFence is always transferred to the callee, even
-    // on errors.
-    Error lock(buffer_handle_t bufferHandle, uint64_t usage,
-            const IMapper::Rect& accessRegion,
-            int acquireFence, YCbCrLayout* outLayout) const;
+    status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                  int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                  int32_t* outBytesPerStride) const override;
 
-    // unlock returns a fence sync object (or -1) and the fence sync object is
-    // owned by the caller
-    int unlock(buffer_handle_t bufferHandle) const;
+    status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                  int acquireFence, android_ycbcr* ycbcr) const override;
+
+    int unlock(buffer_handle_t bufferHandle) const override;
+
+    status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+                         uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
 
 private:
     // Determines whether the passed info is compatible with the mapper.
-    Error validateBufferDescriptorInfo(
-            const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+    status_t validateBufferDescriptorInfo(
+            hardware::graphics::mapper::V2_1::IMapper::BufferDescriptorInfo* descriptorInfo) const;
 
     sp<hardware::graphics::mapper::V2_0::IMapper> mMapper;
-    sp<IMapper> mMapperV2_1;
+    sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
 };
 
-// A wrapper to IAllocator
-class Allocator {
+class Gralloc2Allocator : public GrallocAllocator {
 public:
     // An allocator relies on a mapper, and that mapper must be alive at all
     // time.
-    Allocator(const Mapper& mapper);
+    Gralloc2Allocator(const Gralloc2Mapper& mapper);
 
-    std::string dumpDebugInfo() const;
+    bool isLoaded() const override;
 
-    /*
-     * The returned buffers are already imported and must not be imported
-     * again.  outBufferHandles must point to a space that can contain at
-     * least "count" buffer_handle_t.
-     */
-    Error allocate(BufferDescriptor descriptor, uint32_t count,
-            uint32_t* outStride, buffer_handle_t* outBufferHandles) const;
+    std::string dumpDebugInfo() const override;
 
-    Error allocate(BufferDescriptor descriptor,
-            uint32_t* outStride, buffer_handle_t* outBufferHandle) const
-    {
-        return allocate(descriptor, 1, outStride, outBufferHandle);
-    }
-
-    Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t count,
-            uint32_t* outStride, buffer_handle_t* outBufferHandles) const
-    {
-        BufferDescriptor descriptor;
-        Error error = mMapper.createDescriptor(descriptorInfo, &descriptor);
-        if (error == Error::NONE) {
-            error = allocate(descriptor, count, outStride, outBufferHandles);
-        }
-        return error;
-    }
-
-    Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-            uint32_t* outStride, buffer_handle_t* outBufferHandle) const
-    {
-        return allocate(descriptorInfo, 1, outStride, outBufferHandle);
-    }
+    status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+                      uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+                      buffer_handle_t* outBufferHandles) const override;
 
 private:
-    const Mapper& mMapper;
-    sp<IAllocator> mAllocator;
+    const Gralloc2Mapper& mMapper;
+    sp<hardware::graphics::allocator::V2_0::IAllocator> mAllocator;
 };
 
-} // namespace Gralloc2
-
 } // namespace android
 
 #endif // ANDROID_UI_GRALLOC2_H
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
new file mode 100644
index 0000000..0965f52
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC3_H
+#define ANDROID_UI_GRALLOC3_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Gralloc3Mapper : public GrallocMapper {
+public:
+    static void preload();
+
+    Gralloc3Mapper();
+
+    bool isLoaded() const override;
+
+    status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
+
+    status_t importBuffer(const hardware::hidl_handle& rawHandle,
+                          buffer_handle_t* outBufferHandle) const override;
+
+    void freeBuffer(buffer_handle_t bufferHandle) const override;
+
+    status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+                                android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+                                uint32_t stride) const override;
+
+    void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+                          uint32_t* outNumInts) const override;
+
+    status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                  int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                  int32_t* outBytesPerStride) const override;
+
+    status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+                  int acquireFence, android_ycbcr* ycbcr) const override;
+
+    int unlock(buffer_handle_t bufferHandle) const override;
+
+    status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+                         uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
+
+private:
+    // Determines whether the passed info is compatible with the mapper.
+    status_t validateBufferDescriptorInfo(
+            hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo* descriptorInfo) const;
+
+    sp<hardware::graphics::mapper::V3_0::IMapper> mMapper;
+};
+
+class Gralloc3Allocator : public GrallocAllocator {
+public:
+    // An allocator relies on a mapper, and that mapper must be alive at all
+    // time.
+    Gralloc3Allocator(const Gralloc3Mapper& mapper);
+
+    bool isLoaded() const override;
+
+    std::string dumpDebugInfo() const override;
+
+    status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+                      uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+                      buffer_handle_t* outBufferHandles) const override;
+
+private:
+    const Gralloc3Mapper& mMapper;
+    sp<hardware::graphics::allocator::V3_0::IAllocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC3_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index cc38982..c195342 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -21,8 +21,12 @@
 #include <sys/types.h>
 
 #include <string>
+#include <utility>
+#include <vector>
 
+#include <android/hardware_buffer.h>
 #include <ui/ANativeObjectBase.h>
+#include <ui/GraphicBufferMapper.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
 #include <utils/Flattenable.h>
@@ -34,9 +38,14 @@
 
 namespace android {
 
-class DetachedBufferHandle;
+#ifndef LIBUI_IN_VNDK
+class BufferHubBuffer;
+#endif // LIBUI_IN_VNDK
+
 class GraphicBufferMapper;
 
+using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>;
+
 // ===========================================================================
 // GraphicBuffer
 // ===========================================================================
@@ -75,6 +84,10 @@
 
     static sp<GraphicBuffer> from(ANativeWindowBuffer *);
 
+    static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*);
+    static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*);
+    AHardwareBuffer* toAHardwareBuffer();
+    AHardwareBuffer const* toAHardwareBuffer() const;
 
     // Create a GraphicBuffer to be unflatten'ed into or be reallocated.
     GraphicBuffer();
@@ -118,24 +131,27 @@
         // cannot be used directly, such as one from hidl_handle.
         CLONE_HANDLE,
     };
-    GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
-            uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount,
-            uint64_t usage, uint32_t stride);
+    GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+                  uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
+                  uint32_t inStride);
 
     // These functions are deprecated because they only take 32 bits of usage
-    GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
-            uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount,
-            uint32_t usage, uint32_t stride)
-        : GraphicBuffer(handle, method, width, height, format, layerCount,
-                static_cast<uint64_t>(usage), stride) {}
+    GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+                  uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+                  uint32_t inStride)
+          : GraphicBuffer(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+                          static_cast<uint64_t>(inUsage), inStride) {}
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
             uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
             native_handle_t* inHandle, bool keepOwnership);
     GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
             uint32_t inUsage, std::string requestorName = "<Unknown>");
 
+#ifndef LIBUI_IN_VNDK
+    // Create a GraphicBuffer from an existing BufferHubBuffer.
+    GraphicBuffer(std::unique_ptr<BufferHubBuffer> buffer);
+#endif // LIBUI_IN_VNDK
+
     // return status
     status_t initCheck() const;
 
@@ -147,6 +163,7 @@
     uint32_t getLayerCount() const      { return static_cast<uint32_t>(layerCount); }
     Rect getBounds() const              { return Rect(width, height); }
     uint64_t getId() const              { return mId; }
+    int32_t getBufferId() const { return mBufferId; }
 
     uint32_t getGenerationNumber() const { return mGenerationNumber; }
     void setGenerationNumber(uint32_t generation) {
@@ -162,24 +179,35 @@
     bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
             PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage);
 
-    status_t lock(uint32_t inUsage, void** vaddr);
-    status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
+    // For the following two lock functions, if bytesPerStride or bytesPerPixel
+    // are unknown or variable, -1 will be returned
+    status_t lock(uint32_t inUsage, void** vaddr, int32_t* outBytesPerPixel = nullptr,
+                  int32_t* outBytesPerStride = nullptr);
+    status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr,
+                  int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
     // For HAL_PIXEL_FORMAT_YCbCr_420_888
     status_t lockYCbCr(uint32_t inUsage, android_ycbcr *ycbcr);
     status_t lockYCbCr(uint32_t inUsage, const Rect& rect,
             android_ycbcr *ycbcr);
     status_t unlock();
-    status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd);
-    status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr,
-            int fenceFd);
-    status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
-            const Rect& rect, void** vaddr, int fenceFd);
+    // For the following three lockAsync functions, if bytesPerStride or bytesPerPixel
+    // are unknown or variable, -1 will be returned
+    status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd,
+                       int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+    status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, int fenceFd,
+                       int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
+    status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage, const Rect& rect,
+                       void** vaddr, int fenceFd, int32_t* outBytesPerPixel = nullptr,
+                       int32_t* outBytesPerStride = nullptr);
     status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
             int fenceFd);
     status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
             android_ycbcr *ycbcr, int fenceFd);
     status_t unlockAsync(int *fenceFd);
 
+    status_t isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                         uint32_t inLayerCount, uint64_t inUsage, bool* outSupported) const;
+
     ANativeWindowBuffer* getNativeBuffer() const;
 
     // for debugging
@@ -191,10 +219,16 @@
     status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
     status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
 
-    // Sets and takes DetachedBuffer. Should only be called from BufferHub.
-    bool isDetachedBuffer() const;
-    status_t setDetachedBufferHandle(std::unique_ptr<DetachedBufferHandle> detachedBuffer);
-    std::unique_ptr<DetachedBufferHandle> takeDetachedBufferHandle();
+    GraphicBufferMapper::Version getBufferMapperVersion() const {
+        return mBufferMapper.getMapperVersion();
+    }
+
+    void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context);
+
+#ifndef LIBUI_IN_VNDK
+    // Returns whether this GraphicBuffer is backed by BufferHubBuffer.
+    bool isBufferHubBuffer() const;
+#endif // LIBUI_IN_VNDK
 
 private:
     ~GraphicBuffer();
@@ -226,10 +260,9 @@
             PixelFormat inFormat, uint32_t inLayerCount,
             uint64_t inUsage, std::string requestorName);
 
-    status_t initWithHandle(const native_handle_t* handle,
-            HandleWrapMethod method, uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t layerCount,
-            uint64_t usage, uint32_t stride);
+    status_t initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+                            uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+                            uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride);
 
     void free_handle();
 
@@ -242,21 +275,46 @@
 
     uint64_t mId;
 
+    // System unique buffer ID. Note that this is different from mId, which is process unique. For
+    // GraphicBuffer backed by BufferHub, the mBufferId is a system unique identifier that stays the
+    // same cross process for the same chunck of underlying memory. Also note that this only applies
+    // to GraphicBuffers that are backed by BufferHub.
+    int32_t mBufferId = -1;
+
     // Stores the generation number of this buffer. If this number does not
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
 
-    // Stores a BufferHub handle that can be used to re-attach this GraphicBuffer back into a
-    // BufferHub producer/consumer set. In terms of GraphicBuffer's relationship with BufferHub,
-    // there are three different modes:
-    // 1. Legacy mode: GraphicBuffer is not backed by BufferHub and mDetachedBufferHandle must be
-    //    invalid.
-    // 2. Detached mode: GraphicBuffer is backed by BufferHub, but not part of a producer/consumer
-    //    set. In this mode, mDetachedBufferHandle must be valid.
-    // 3. Attached mode: GraphicBuffer is backed by BufferHub and it's part of a producer/consumer
-    //    set. In this mode, mDetachedBufferHandle must be invalid.
-    std::unique_ptr<DetachedBufferHandle> mDetachedBufferHandle;
+    // Send a callback when a GraphicBuffer dies.
+    //
+    // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When
+    // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes
+    // problems when trying to implicitcly cache across process boundaries. Ideally, both sides
+    // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer
+    // would be destroyed. Unfortunately, when SurfaceFlinger has only a wp<> reference to the
+    // GraphicBuffer, it immediately goes out of scope in the SurfaceFlinger process. SurfaceFlinger
+    // must hold onto a sp<> to the buffer. When the GraphicBuffer goes out of scope in the app's
+    // process, the client side cache will get this callback. It erases the buffer from its cache
+    // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer.
+    std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>>
+            mDeathCallbacks;
+
+#ifndef LIBUI_IN_VNDK
+    // Flatten this GraphicBuffer object if backed by BufferHubBuffer.
+    status_t flattenBufferHubBuffer(void*& buffer, size_t& size) const;
+
+    // Unflatten into BufferHubBuffer backed GraphicBuffer.
+    // Unflatten will fail if the original GraphicBuffer object is destructed. For instance, a
+    // GraphicBuffer backed by BufferHubBuffer_1 flatten in process/thread A, transport the token
+    // to process/thread B through a socket, BufferHubBuffer_1 dies and bufferhub invalidated the
+    // token. Race condition occurs between the invalidation of the token in bufferhub process and
+    // process/thread B trying to unflatten and import the buffer with that token.
+    status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size);
+
+    // Stores a BufferHubBuffer that handles buffer signaling, identification.
+    std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
+#endif // LIBUI_IN_VNDK
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 14a865e..25d4512 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -34,12 +34,8 @@
 
 namespace android {
 
-namespace Gralloc2 {
-class Allocator;
-}
-
+class GrallocAllocator;
 class GraphicBufferMapper;
-class String8;
 
 class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
 {
@@ -53,7 +49,9 @@
 
     status_t free(buffer_handle_t handle);
 
-    void dump(String8& res) const;
+    size_t getTotalSize() const;
+
+    void dump(std::string& res) const;
     static void dumpToSystemLog();
 
 private:
@@ -76,7 +74,7 @@
     ~GraphicBufferAllocator();
 
     GraphicBufferMapper& mMapper;
-    const std::unique_ptr<const Gralloc2::Allocator> mAllocator;
+    std::unique_ptr<const GrallocAllocator> mAllocator;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 7cf003d..2461454 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -35,15 +35,16 @@
 
 // ---------------------------------------------------------------------------
 
-namespace Gralloc2 {
-class Mapper;
-}
-
+class GrallocMapper;
 class Rect;
 
 class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
 {
 public:
+    enum Version {
+        GRALLOC_2,
+        GRALLOC_3,
+    };
     static void preloadHal();
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
@@ -59,20 +60,21 @@
     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);
+    status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
+                  int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
 
     status_t lockYCbCr(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr);
 
     status_t unlock(buffer_handle_t handle);
 
-    status_t lockAsync(buffer_handle_t handle,
-            uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd);
+    status_t lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
+                       int fenceFd, int32_t* outBytesPerPixel = nullptr,
+                       int32_t* outBytesPerStride = nullptr);
 
-    status_t lockAsync(buffer_handle_t handle,
-            uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
-            void** vaddr, int fenceFd);
+    status_t lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage,
+                       const Rect& bounds, void** vaddr, int fenceFd,
+                       int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
 
     status_t lockAsyncYCbCr(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
@@ -80,17 +82,23 @@
 
     status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
 
-    const Gralloc2::Mapper& getGrallocMapper() const
-    {
-        return *mMapper;
+    status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+                         uint32_t layerCount, uint64_t usage, bool* outSupported);
+
+    const GrallocMapper& getGrallocMapper() const {
+        return reinterpret_cast<const GrallocMapper&>(*mMapper);
     }
 
+    Version getMapperVersion() const { return mMapperVersion; }
+
 private:
     friend class Singleton<GraphicBufferMapper>;
 
     GraphicBufferMapper();
 
-    const std::unique_ptr<const Gralloc2::Mapper> mMapper;
+    std::unique_ptr<const GrallocMapper> mMapper;
+
+    Version mMapperVersion;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 0fa819d..5dc56c8 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -16,19 +16,28 @@
 
 #pragma once
 
+#include <cinttypes>
+#include <cstdint>
+
 #include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
 #include <system/graphics.h>
 
+#define ANDROID_PHYSICAL_DISPLAY_ID_FORMAT PRIu64
+
+namespace android {
+
+using PhysicalDisplayId = uint64_t;
+
 // android::ui::* in this header file will alias different types as
 // the HIDL interface is updated.
-namespace android {
 namespace ui {
 
-using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
-using android::hardware::graphics::common::V1_1::PixelFormat;
 using android::hardware::graphics::common::V1_1::RenderIntent;
+using android::hardware::graphics::common::V1_2::ColorMode;
+using android::hardware::graphics::common::V1_2::Dataspace;
+using android::hardware::graphics::common::V1_2::Hdr;
+using android::hardware::graphics::common::V1_2::PixelFormat;
 
 }  // namespace ui
 }  // namespace android
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 4e98c28..65ac26c 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -37,8 +37,8 @@
         mMinLuminance(minLuminance) {}
 
     // Make this move-constructable and move-assignable
-    HdrCapabilities(HdrCapabilities&& other);
-    HdrCapabilities& operator=(HdrCapabilities&& other);
+    HdrCapabilities(HdrCapabilities&& other) noexcept;
+    HdrCapabilities& operator=(HdrCapabilities&& other) noexcept;
 
     HdrCapabilities()
       : mSupportedHdrTypes(),
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
new file mode 100644
index 0000000..1152cc5
--- /dev/null
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UI_PUBLICFORMAT_H
+#define UI_PUBLICFORMAT_H
+
+#include <system/graphics.h>
+
+namespace android {
+
+/**
+ * Enum mirroring the public API definitions for image and pixel formats.
+ * Some of these are hidden in the public API
+ *
+ * Keep up to date with android.graphics.ImageFormat and
+ * android.graphics.PixelFormat
+ *
+ * TODO: PublicFormat is going to be deprecated(b/126594675)
+ */
+enum class PublicFormat {
+    UNKNOWN = 0x0,
+    RGBA_8888 = 0x1,
+    RGBX_8888 = 0x2,
+    RGB_888 = 0x3,
+    RGB_565 = 0x4,
+    NV16 = 0x10,
+    NV21 = 0x11,
+    YUY2 = 0x14,
+    RGBA_FP16 = 0x16,
+    RAW_SENSOR = 0x20,
+    PRIVATE = 0x22,
+    YUV_420_888 = 0x23,
+    RAW_PRIVATE = 0x24,
+    RAW10 = 0x25,
+    RAW12 = 0x26,
+    RGBA_1010102 = 0x2b,
+    JPEG = 0x100,
+    DEPTH_POINT_CLOUD = 0x101,
+    RAW_DEPTH = 0x1002, // @hide
+    YV12 = 0x32315659,
+    Y8 = 0x20203859,
+    Y16 = 0x20363159, // @hide
+    DEPTH16 = 0x44363159,
+    DEPTH_JPEG = 0x69656963,
+    HEIC = 0x48454946,
+};
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * format */
+extern int mapPublicFormatToHalFormat(PublicFormat f);
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * dataspace */
+extern android_dataspace mapPublicFormatToHalDataspace(PublicFormat f);
+
+/* Convert from HAL format, dataspace pair to
+ * android.graphics.ImageFormat/PixelFormat.
+ * For unknown/unspecified pairs, returns PublicFormat::UNKNOWN */
+extern PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace);
+
+}; // namespace android
+
+#endif // UI_PUBLICFORMAT_H
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 0bec0b7..1768805 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -24,6 +24,7 @@
 
 #include <ui/FloatRect.h>
 #include <ui/Point.h>
+#include <ui/Size.h>
 
 #include <android/rect.h>
 
@@ -78,6 +79,13 @@
         bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
     }
 
+    inline explicit Rect(const ui::Size& size) {
+        left = 0;
+        top = 0;
+        right = size.width;
+        bottom = size.height;
+    }
+
     void makeInvalid();
 
     inline void clear() {
@@ -106,6 +114,8 @@
         return bottom - top;
     }
 
+    ui::Size getSize() const { return ui::Size(getWidth(), getHeight()); }
+
     __attribute__((no_sanitize("signed-integer-overflow")))
     inline Rect getBounds() const {
         return Rect(right - left, bottom - top);
@@ -120,7 +130,7 @@
         right = rb.x;
         bottom = rb.y;
     }
-    
+
     // the following 4 functions return the 4 corners of the rect as Point
     Point leftTop() const {
         return Point(left, top);
@@ -175,6 +185,11 @@
     Rect& offsetTo(int32_t x, int32_t y);
     Rect& offsetBy(int32_t x, int32_t y);
 
+    /**
+     * Insets the rectangle on all sides specified by the insets.
+     */
+    Rect& inset(int32_t _left, int32_t _top, int32_t _right, int32_t _bottom);
+
     bool intersect(const Rect& with, Rect* result) const;
 
     // Create a new Rect by transforming this one using a graphics HAL
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 7788452..79642ae 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -25,12 +25,13 @@
 #include <ui/Rect.h>
 #include <utils/Flattenable.h>
 
+#include <android-base/macros.h>
+
+#include <string>
+
 namespace android {
 // ---------------------------------------------------------------------------
 
-class String8;
-
-// ---------------------------------------------------------------------------
 class Region : public LightFlattenable<Region>
 {
 public:
@@ -87,17 +88,19 @@
 
             // these translate rhs first
             Region&     translateSelf(int dx, int dy);
+            Region&     scaleSelf(float sx, float sy);
             Region&     orSelf(const Region& rhs, int dx, int dy);
             Region&     xorSelf(const Region& rhs, int dx, int dy);
             Region&     andSelf(const Region& rhs, int dx, int dy);
             Region&     subtractSelf(const Region& rhs, int dx, int dy);
 
+
             // these translate rhs first
-    const   Region      translate(int dx, int dy) const;
-    const   Region      merge(const Region& rhs, int dx, int dy) const;
-    const   Region      mergeExclusive(const Region& rhs, int dx, int dy) const;
-    const   Region      intersect(const Region& rhs, int dx, int dy) const;
-    const   Region      subtract(const Region& rhs, int dx, int dy) const;
+    const   Region      translate(int dx, int dy) const WARN_UNUSED;
+    const   Region      merge(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+    const   Region      mergeExclusive(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+    const   Region      intersect(const Region& rhs, int dx, int dy) const WARN_UNUSED;
+    const   Region      subtract(const Region& rhs, int dx, int dy) const WARN_UNUSED;
 
     // convenience operators overloads
     inline  const Region      operator | (const Region& rhs) const;
@@ -140,8 +143,8 @@
             status_t    flatten(void* buffer, size_t size) const;
             status_t    unflatten(void const* buffer, size_t size);
 
-    void        dump(String8& out, const char* what, uint32_t flags=0) const;
-    void        dump(const char* what, uint32_t flags=0) const;
+            void        dump(std::string& out, const char* what, uint32_t flags=0) const;
+            void        dump(const char* what, uint32_t flags=0) const;
 
 private:
     class rasterizer;
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
new file mode 100644
index 0000000..c39d8af
--- /dev/null
+++ b/libs/ui/include/ui/Size.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace android {
+namespace ui {
+
+// Forward declare a few things.
+struct Size;
+bool operator==(const Size& lhs, const Size& rhs);
+
+/**
+ * A simple value type representing a two-dimensional size
+ */
+struct Size {
+    int32_t width;
+    int32_t height;
+
+    // Special values
+    static const Size INVALID;
+    static const Size EMPTY;
+
+    // ------------------------------------------------------------------------
+    // Construction
+    // ------------------------------------------------------------------------
+
+    Size() : Size(INVALID) {}
+    template <typename T>
+    Size(T&& w, T&& h)
+          : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
+            height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    int32_t getWidth() const { return width; }
+    int32_t getHeight() const { return height; }
+
+    template <typename T>
+    void setWidth(T&& v) {
+        width = Size::clamp<int32_t, T>(std::forward<T>(v));
+    }
+    template <typename T>
+    void setHeight(T&& v) {
+        height = Size::clamp<int32_t, T>(std::forward<T>(v));
+    }
+
+    // ------------------------------------------------------------------------
+    // Assignment
+    // ------------------------------------------------------------------------
+
+    void set(const Size& size) { *this = size; }
+    template <typename T>
+    void set(T&& w, T&& h) {
+        set(Size(std::forward<T>(w), std::forward<T>(h)));
+    }
+
+    // Sets the value to INVALID
+    void makeInvalid() { set(INVALID); }
+
+    // Sets the value to EMPTY
+    void clear() { set(EMPTY); }
+
+    // ------------------------------------------------------------------------
+    // Semantic checks
+    // ------------------------------------------------------------------------
+
+    // Valid means non-negative width and height
+    bool isValid() const { return width >= 0 && height >= 0; }
+
+    // Empty means zero width and height
+    bool isEmpty() const { return *this == EMPTY; }
+
+    // ------------------------------------------------------------------------
+    // Clamp Helpers
+    // ------------------------------------------------------------------------
+
+    // Note: We use only features available in C++11 here for compatibility with
+    // external targets which include this file directly or indirectly and which
+    // themselves use C++11.
+
+    // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
+    template <typename T>
+    using remove_cv_reference_t =
+            typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+    // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
+    // clamping the input value to the output range if necessary.
+    template <typename ToType, typename FromType>
+    static Size::remove_cv_reference_t<ToType> clamp(
+            typename std::enable_if<
+                    std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
+                            std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
+                    FromType&&>::type v) {
+        static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
+        static constexpr auto toLowest =
+                std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
+        static constexpr auto fromHighest =
+                std::numeric_limits<remove_cv_reference_t<FromType>>::max();
+        static constexpr auto fromLowest =
+                std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
+
+        // A clamp is needed if the range of FromType is not a subset of the range of ToType
+        static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
+
+        // If a clamp is not needed, the conversion is just a trivial cast.
+        if (!isClampNeeded) {
+            return static_cast<ToType>(v);
+        }
+
+        // Otherwise we leverage implicit conversion to safely compare values of
+        // different types, to ensure we return a value clamped to the range of
+        // ToType.
+        return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+    }
+};
+
+// ------------------------------------------------------------------------
+// Comparisons
+// ------------------------------------------------------------------------
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+    return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+    return !operator==(lhs, rhs);
+}
+
+inline bool operator<(const Size& lhs, const Size& rhs) {
+    // Orders by increasing width, then height.
+    if (lhs.width != rhs.width) return lhs.width < rhs.width;
+    return lhs.height < rhs.height;
+}
+
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
new file mode 100644
index 0000000..f29a370
--- /dev/null
+++ b/libs/ui/include/ui/Transform.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2007 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_TRANSFORM_H
+#define ANDROID_TRANSFORM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <string>
+
+#include <hardware/hardware.h>
+#include <math/mat4.h>
+#include <math/vec2.h>
+#include <math/vec3.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+class Region;
+
+namespace ui {
+
+class Transform {
+public:
+    Transform();
+    Transform(const Transform&  other);
+    explicit Transform(uint32_t orientation);
+    ~Transform();
+
+    enum orientation_flags {
+        ROT_0   = 0x00000000,
+        FLIP_H  = HAL_TRANSFORM_FLIP_H,
+        FLIP_V  = HAL_TRANSFORM_FLIP_V,
+        ROT_90  = HAL_TRANSFORM_ROT_90,
+        ROT_180 = FLIP_H|FLIP_V,
+        ROT_270 = ROT_180|ROT_90,
+        ROT_INVALID = 0x80
+    };
+
+    enum type_mask : uint32_t {
+        IDENTITY            = 0,
+        TRANSLATE           = 0x1,
+        ROTATE              = 0x2,
+        SCALE               = 0x4,
+        UNKNOWN             = 0x8
+    };
+
+    // query the transform
+    bool        preserveRects() const;
+    uint32_t    getType() const;
+    uint32_t    getOrientation() const;
+
+    const vec3& operator [] (size_t i) const;  // returns column i
+    float   tx() const;
+    float   ty() const;
+    float   sx() const;
+    float   sy() const;
+
+    // modify the transform
+    void        reset();
+    void        set(float tx, float ty);
+    void        set(float a, float b, float c, float d);
+    status_t    set(uint32_t flags, float w, float h);
+
+    // transform data
+    Rect    makeBounds(int w, int h) const;
+    vec2    transform(int x, int y) const;
+    Region  transform(const Region& reg) const;
+    Rect    transform(const Rect& bounds,
+                      bool roundOutwards = false) const;
+    FloatRect transform(const FloatRect& bounds) const;
+    Transform& operator = (const Transform& other);
+    Transform operator * (const Transform& rhs) const;
+    // assumes the last row is < 0 , 0 , 1 >
+    vec2 transform(const vec2& v) const;
+    vec3 transform(const vec3& v) const;
+
+    // Expands from the internal 3x3 matrix to an equivalent 4x4 matrix
+    mat4 asMatrix4() const;
+
+    Transform inverse() const;
+
+    // for debugging
+    void dump(std::string& result, const char* name) const;
+    void dump(const char* name) const;
+
+private:
+    struct mat33 {
+        vec3 v[3];
+        inline const vec3& operator [] (size_t i) const { return v[i]; }
+        inline vec3& operator [] (size_t i) { return v[i]; }
+    };
+
+    enum { UNKNOWN_TYPE = 0x80000000 };
+
+    uint32_t type() const;
+    static bool absIsOne(float f);
+    static bool isZero(float f);
+
+    mat33               mMatrix;
+    mutable uint32_t    mType;
+};
+
+}  // namespace ui
+}  // namespace android
+
+#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/ui/include/ui/UiConfig.h b/libs/ui/include/ui/UiConfig.h
index fcf8ed5..d1d6014 100644
--- a/libs/ui/include/ui/UiConfig.h
+++ b/libs/ui/include/ui/UiConfig.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_UI_CONFIG_H
 #define ANDROID_UI_CONFIG_H
 
-#include <utils/String8.h>
+#include <string>
 
 namespace android {
 
 // Append the libui configuration details to configStr.
-void appendUiConfigString(String8& configStr);
+void appendUiConfigString(std::string& configStr);
 
 }; // namespace android
 
diff --git a/libs/ui/include_vndk/ui/ConfigStoreTypes.h b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
new file mode 100644
index 0000000..4445ae9
--- /dev/null
+++ b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// android::ui::* in this header file will alias different types as
+// the HIDL interface is updated.
+namespace android {
+namespace ui {
+
+struct CieXyz {
+    float X;
+    float Y;
+    float Z;
+};
+struct DisplayPrimaries {
+    CieXyz red;
+    CieXyz green;
+    CieXyz blue;
+    CieXyz white;
+};
+
+}  // namespace ui
+}  // namespace android
diff --git a/libs/ui/include_vndk/ui/DisplayedFrameStats.h b/libs/ui/include_vndk/ui/DisplayedFrameStats.h
new file mode 120000
index 0000000..6014e19
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayedFrameStats.h
@@ -0,0 +1 @@
+../../include/ui/DisplayedFrameStats.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Size.h b/libs/ui/include_vndk/ui/Size.h
new file mode 120000
index 0000000..fd2b21b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Size.h
@@ -0,0 +1 @@
+../../include/ui/Size.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/Transform.h b/libs/ui/include_vndk/ui/Transform.h
new file mode 120000
index 0000000..60633c2
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Transform.h
@@ -0,0 +1 @@
+../../include/ui/Transform.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index aef6428..373fa4f 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -30,7 +30,51 @@
 
 cc_test {
     name: "GraphicBuffer_test",
-    shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+    header_libs: [
+        "libdvr_headers",
+        "libnativewindow_headers",
+    ],
+    shared_libs: [
+        "android.frameworks.bufferhub@1.0",
+        "libcutils",
+        "libhidlbase",
+        "libhwbinder",
+        "libui",
+        "libutils",
+    ],
     srcs: ["GraphicBuffer_test.cpp"],
     cflags: ["-Wall", "-Werror"],
 }
+
+cc_test {
+    name: "BufferHub_test",
+    header_libs: [
+        "libdvr_headers",
+        "libnativewindow_headers",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    shared_libs: [
+        "android.frameworks.bufferhub@1.0",
+        "libcutils",
+        "libhidlbase",
+        "libhwbinder",
+        "liblog",
+        "libui",
+        "libutils"
+    ],
+    srcs: [
+        "BufferHubBuffer_test.cpp",
+        "BufferHubEventFd_test.cpp",
+        "BufferHubMetadata_test.cpp",
+    ],
+    cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
+    name: "Size_test",
+    shared_libs: ["libui"],
+    srcs: ["Size_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
new file mode 100644
index 0000000..0c73a72
--- /dev/null
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferHubBufferTest"
+
+#include <errno.h>
+#include <sys/epoll.h>
+
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/BufferHubBuffer.h>
+#include <ui/BufferHubEventFd.h>
+
+namespace android {
+
+namespace {
+
+using ::android::BufferHubDefs::isAnyClientAcquired;
+using ::android::BufferHubDefs::isAnyClientGained;
+using ::android::BufferHubDefs::isAnyClientPosted;
+using ::android::BufferHubDefs::isClientAcquired;
+using ::android::BufferHubDefs::isClientGained;
+using ::android::BufferHubDefs::isClientPosted;
+using ::android::BufferHubDefs::isClientReleased;
+using ::android::BufferHubDefs::kMetadataHeaderSize;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const AHardwareBuffer_Desc kDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
+                                    kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+const size_t kUserMetadataSize = 1;
+
+class BufferHubBufferTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        android::hardware::ProcessState::self()->startThreadPool();
+
+        if (!BufferHubServiceRunning()) {
+            // TODO(b/112940221): Enforce the test cross all devices once BufferHub lands in Android
+            // R for all Android varieties.
+            GTEST_SKIP() << "Skip test as the BufferHub service is not running.";
+        }
+    }
+
+    bool BufferHubServiceRunning() {
+        sp<IBufferHub> bufferhub = IBufferHub::getService();
+        return bufferhub.get() != nullptr;
+    }
+};
+
+bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) {
+    // Not comparing stride because it's unknown before allocation
+    return desc.format == other.format && desc.height == other.height &&
+            desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width;
+}
+
+class BufferHubBufferStateTransitionTest : public BufferHubBufferTest {
+protected:
+    void SetUp() override {
+        BufferHubBufferTest::SetUp();
+
+        if (IsSkipped()) {
+            // If the base class' SetUp() stated the test should be skipped, we should short
+            // circuit this sub-class' logic.
+            return;
+        }
+
+        CreateTwoClientsOfABuffer();
+    }
+
+    std::unique_ptr<BufferHubBuffer> b1;
+    uint32_t b1ClientMask = 0U;
+    std::unique_ptr<BufferHubBuffer> b2;
+    uint32_t b2ClientMask = 0U;
+
+private:
+    // Creates b1 and b2 as the clients of the same buffer for testing.
+    void CreateTwoClientsOfABuffer();
+};
+
+void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
+    b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    b1ClientMask = b1->clientStateMask();
+    ASSERT_NE(b1ClientMask, 0U);
+
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    b2 = BufferHubBuffer::import(token);
+    ASSERT_THAT(b2, NotNull());
+
+    b2ClientMask = b2->clientStateMask();
+    ASSERT_NE(b2ClientMask, 0U);
+    ASSERT_NE(b2ClientMask, b1ClientMask);
+}
+
+TEST_F(BufferHubBufferTest, CreateBufferFails) {
+    // Buffer Creation will fail: BLOB format requires height to be 1.
+    auto b1 = BufferHubBuffer::create(kWidth, /*height=*/2, kLayerCount,
+                                      /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
+
+    EXPECT_THAT(b1, IsNull());
+
+    // Buffer Creation will fail: user metadata size too large.
+    auto b2 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      /*userMetadataSize=*/std::numeric_limits<size_t>::max());
+
+    EXPECT_THAT(b2, IsNull());
+
+    // Buffer Creation will fail: user metadata size too large.
+    const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
+    auto b3 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      userMetadataSize);
+
+    EXPECT_THAT(b3, IsNull());
+}
+
+TEST_F(BufferHubBufferTest, CreateBuffer) {
+    auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    EXPECT_TRUE(b1->isConnected());
+    EXPECT_TRUE(b1->isValid());
+    EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc));
+    EXPECT_EQ(b1->userMetadataSize(), kUserMetadataSize);
+}
+
+TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
+    auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    EXPECT_TRUE(b1->isValid());
+
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    // The detached buffer should still be valid.
+    EXPECT_TRUE(b1->isConnected());
+    EXPECT_TRUE(b1->isValid());
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
+
+    ASSERT_THAT(b2, NotNull());
+    EXPECT_TRUE(b2->isValid());
+
+    EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc()));
+    EXPECT_EQ(b1->userMetadataSize(), b2->userMetadataSize());
+
+    // These two buffer instances are based on the same physical buffer under the
+    // hood, so they should share the same id.
+    EXPECT_EQ(b1->id(), b2->id());
+    // We use clientStateMask() to tell those two instances apart.
+    EXPECT_NE(b1->clientStateMask(), b2->clientStateMask());
+
+    // Both buffer instances should be in released state currently.
+    EXPECT_TRUE(b1->isReleased());
+    EXPECT_TRUE(b2->isReleased());
+
+    // The event fd should behave like duped event fds.
+    const BufferHubEventFd& eventFd1 = b1->eventFd();
+    ASSERT_GE(eventFd1.get(), 0);
+    const BufferHubEventFd& eventFd2 = b2->eventFd();
+    ASSERT_GE(eventFd2.get(), 0);
+
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+
+    // Add eventFd1 to epoll set, and signal eventFd2.
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e), 0) << strerror(errno);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd2.signal();
+    eventFd2.clear();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
+    auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                      kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    EXPECT_TRUE(b1->isValid());
+
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid
+    b1.reset();
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
+
+    // Import should fail with INVALID_TOKEN
+    EXPECT_THAT(b2, IsNull());
+}
+
+// nullptr must not crash the service
+TEST_F(BufferHubBufferTest, ImportNullToken) {
+    auto b1 = BufferHubBuffer::import(nullptr);
+    EXPECT_THAT(b1, IsNull());
+}
+
+TEST_F(BufferHubBufferTest, ImportInvalidToken) {
+    native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+    token->data[0] = 0;
+
+    sp<NativeHandle> tokenHandle = NativeHandle::create(token, /*ownHandle=*/true);
+    auto b1 = BufferHubBuffer::import(tokenHandle);
+
+    EXPECT_THAT(b1, IsNull());
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
+    ASSERT_TRUE(b1->isReleased());
+
+    // Successful gaining the buffer should change the buffer state bit of b1 to
+    // gained state, other client state bits to released state.
+    EXPECT_EQ(b1->gain(), 0);
+    EXPECT_TRUE(isClientGained(b1->bufferState(), b1ClientMask));
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromGainedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    auto currentBufferState = b1->bufferState();
+    ASSERT_TRUE(isClientGained(currentBufferState, b1ClientMask));
+
+    // Gaining from gained state by the same client should not return error.
+    EXPECT_EQ(b1->gain(), 0);
+
+    // Gaining from gained state by another client should return error.
+    EXPECT_EQ(b2->gain(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromAcquiredState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    ASSERT_TRUE(isAnyClientAcquired(b1->bufferState()));
+
+    // Gaining from acquired state should fail.
+    EXPECT_EQ(b1->gain(), -EBUSY);
+    EXPECT_EQ(b2->gain(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromOtherClientInPostedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
+
+    // Gaining a buffer who has other posted client should succeed.
+    EXPECT_EQ(b1->gain(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromSelfInPostedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
+
+    // A posted client should be able to gain the buffer when there is no other clients in
+    // acquired state.
+    EXPECT_EQ(b2->gain(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromOtherInGainedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isClientGained(b1->bufferState(), b1ClientMask));
+
+    EXPECT_EQ(b2->post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromSelfInGainedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isClientGained(b1->bufferState(), b1ClientMask));
+
+    EXPECT_EQ(b1->post(), 0);
+    auto currentBufferState = b1->bufferState();
+    EXPECT_TRUE(isClientReleased(currentBufferState, b1ClientMask));
+    EXPECT_TRUE(isClientPosted(currentBufferState, b2ClientMask));
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromPostedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
+
+    // Post from posted state should fail.
+    EXPECT_EQ(b1->post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromAcquiredState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    ASSERT_TRUE(isAnyClientAcquired(b1->bufferState()));
+
+    // Posting from acquired state should fail.
+    EXPECT_EQ(b1->post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromReleasedState) {
+    ASSERT_TRUE(b1->isReleased());
+
+    // Posting from released state should fail.
+    EXPECT_EQ(b1->post(), -EBUSY);
+    EXPECT_EQ(b2->post(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInPostedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isClientPosted(b1->bufferState(), b2ClientMask));
+
+    // Acquire from posted state should pass.
+    EXPECT_EQ(b2->acquire(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromOtherInPostedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isClientPosted(b1->bufferState(), b2ClientMask));
+
+    // Acquire from released state should fail, although there are other clients
+    // in posted state.
+    EXPECT_EQ(b1->acquire(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInAcquiredState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    auto currentBufferState = b1->bufferState();
+    ASSERT_TRUE(isClientAcquired(currentBufferState, b2ClientMask));
+
+    // Acquiring from acquired state by the same client should not error out.
+    EXPECT_EQ(b2->acquire(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromReleasedState) {
+    ASSERT_TRUE(b1->isReleased());
+
+    // Acquiring form released state should fail.
+    EXPECT_EQ(b1->acquire(), -EBUSY);
+    EXPECT_EQ(b2->acquire(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromGainedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isAnyClientGained(b1->bufferState()));
+
+    // Acquiring from gained state should fail.
+    EXPECT_EQ(b1->acquire(), -EBUSY);
+    EXPECT_EQ(b2->acquire(), -EBUSY);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInReleasedState) {
+    ASSERT_TRUE(b1->isReleased());
+
+    EXPECT_EQ(b1->release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInGainedState) {
+    ASSERT_TRUE(b1->isReleased());
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_TRUE(isAnyClientGained(b1->bufferState()));
+
+    EXPECT_EQ(b1->release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInPostedState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_TRUE(isAnyClientPosted(b1->bufferState()));
+
+    EXPECT_EQ(b2->release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInAcquiredState) {
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+    ASSERT_EQ(b2->acquire(), 0);
+    ASSERT_TRUE(isAnyClientAcquired(b1->bufferState()));
+
+    EXPECT_EQ(b2->release(), 0);
+}
+
+TEST_F(BufferHubBufferStateTransitionTest, BasicUsage) {
+    // 1 producer buffer and 1 consumer buffer initialised in testcase setup.
+    // Test if this set of basic operation succeed:
+    // Producer post three times to the consumer, and released by consumer.
+    for (int i = 0; i < 3; ++i) {
+        ASSERT_EQ(b1->gain(), 0);
+        ASSERT_EQ(b1->post(), 0);
+        ASSERT_EQ(b2->acquire(), 0);
+        ASSERT_EQ(b2->release(), 0);
+    }
+}
+
+TEST_F(BufferHubBufferTest, createNewConsumerAfterGain) {
+    // Create a poducer buffer and gain.
+    std::unique_ptr<BufferHubBuffer> b1 =
+            BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                    kUserMetadataSize);
+    ASSERT_THAT(b1, NotNull());
+    ASSERT_EQ(b1->gain(), 0);
+
+    // Create a consumer of the buffer and test if the consumer can acquire the
+    // buffer if producer posts.
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
+
+    ASSERT_THAT(b2, NotNull());
+    ASSERT_NE(b1->clientStateMask(), b2->clientStateMask());
+
+    ASSERT_EQ(b1->post(), 0);
+    EXPECT_EQ(b2->acquire(), 0);
+}
+
+TEST_F(BufferHubBufferTest, createNewConsumerAfterPost) {
+    // Create a poducer buffer and post.
+    std::unique_ptr<BufferHubBuffer> b1 =
+            BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+                                    kUserMetadataSize);
+    ASSERT_EQ(b1->gain(), 0);
+    ASSERT_EQ(b1->post(), 0);
+
+    // Create a consumer of the buffer and test if the consumer can acquire the
+    // buffer if producer posts.
+    sp<NativeHandle> token = b1->duplicate();
+    ASSERT_THAT(token, NotNull());
+
+    std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::import(token);
+
+    ASSERT_THAT(b2, NotNull());
+    ASSERT_NE(b1->clientStateMask(), b2->clientStateMask());
+
+    EXPECT_EQ(b2->acquire(), 0);
+}
+
+} // namespace
+
+} // namespace android
diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp
new file mode 100644
index 0000000..ef1781f
--- /dev/null
+++ b/libs/ui/tests/BufferHubEventFd_test.cpp
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferHubEventFdTest"
+
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+
+#include <array>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <ui/BufferHubEventFd.h>
+
+namespace android {
+
+namespace {
+
+const int kTimeout = 100;
+const std::chrono::milliseconds kTimeoutMs(kTimeout);
+const int kTestRuns = 5;
+
+using ::testing::Contains;
+using BufferHubEventFdTest = ::testing::Test;
+
+} // namespace
+
+TEST_F(BufferHubEventFdTest, EventFd_testSingleEpollFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Check that it can receive consecutive signal.
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Check that it can receive consecutive signal from a duplicated eventfd.
+    BufferHubEventFd dupEventFd(dup(eventFd.get()));
+    ASSERT_TRUE(dupEventFd.isValid());
+    dupEventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+    dupEventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testCreateEpollFdAndAddSignaledEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+    eventFd.signal();
+
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+
+    // Make sure that the epoll set has not been signal yet.
+    std::array<epoll_event, 1> events;
+    ASSERT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Check that adding an signaled fd into this epoll set will trigger the epoll set.
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testAddSignaledEventFdToEpollFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+
+    eventFd.signal();
+
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromAEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    for (int i = 0; i < kTestRuns; ++i) {
+        eventFd.signal();
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+    }
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromADuplicatedEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+    base::unique_fd epollFd(epoll_create(64));
+    ASSERT_GE(epollFd.get(), 0);
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    BufferHubEventFd dupEventFd(dup(eventFd.get()));
+    ASSERT_TRUE(dupEventFd.isValid());
+
+    std::array<epoll_event, 1> events;
+    for (int i = 0; i < kTestRuns; ++i) {
+        dupEventFd.signal();
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+        EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+    }
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testClear) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    eventFd.signal();
+    eventFd.clear();
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testDupEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    // Technically, the dupliated eventFd and the original eventFd are pointing
+    // to the same kernel object. This test signals the duplicated eventFd but epolls the origianl
+    // eventFd.
+    BufferHubEventFd dupedEventFd(dup(eventFd.get()));
+    ASSERT_GE(dupedEventFd.get(), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    dupedEventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    dupedEventFd.signal();
+
+    dupedEventFd.clear();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoEpollFds) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd1(epoll_create(64));
+    base::unique_fd epollFd2(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd1.get(), 0);
+    ASSERT_GE(epollFd2.get(), 0);
+
+    // Register the same eventFd to two EpollFds.
+    ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1);
+
+    eventFd.clear();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoEventFds) {
+    BufferHubEventFd eventFd1;
+    BufferHubEventFd eventFd2;
+
+    ASSERT_TRUE(eventFd1.isValid());
+    ASSERT_TRUE(eventFd2.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}};
+    epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0);
+
+    std::array<epoll_event, 2> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Signal one by one.
+    eventFd1.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(events[0].data.u32, e1.data.u32);
+
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(events[0].data.u32, e2.data.u32);
+
+    // Signal both.
+    eventFd1.signal();
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 2);
+
+    uint32_t u32s[] = {events[0].data.u32, events[1].data.u32};
+    EXPECT_THAT(u32s, Contains(e1.data.u32));
+    EXPECT_THAT(u32s, Contains(e2.data.u32));
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd1.signal();
+    eventFd2.signal();
+    eventFd2.clear();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testPollingThreadWithTwoEventFds) {
+    BufferHubEventFd eventFd1;
+    BufferHubEventFd eventFd2;
+
+    ASSERT_TRUE(eventFd1.isValid());
+    ASSERT_TRUE(eventFd2.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}};
+    epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0);
+
+    int countEvent1 = 0;
+    int countEvent2 = 0;
+    std::atomic<bool> stop{false};
+    std::mutex mx;
+    std::condition_variable cv;
+
+    std::thread pollingThread([&] {
+        std::array<epoll_event, 2> events;
+        while (true) {
+            if (stop.load()) {
+                break;
+            }
+            int ret = epoll_wait(epollFd.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            std::lock_guard<std::mutex> lock(mx);
+            for (int i = 0; i < ret; i++) {
+                if (events[i].data.u32 == e1.data.u32) {
+                    countEvent1++;
+                    cv.notify_one();
+                } else if (events[i].data.u32 == e2.data.u32) {
+                    countEvent2++;
+                    cv.notify_one();
+                }
+            }
+        }
+    });
+
+    {
+        std::unique_lock<std::mutex> lock(mx);
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 1; }));
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 2; }));
+
+        eventFd2.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 1; }));
+
+        eventFd1.clear();
+        eventFd2.clear();
+        EXPECT_EQ(countEvent1, 2);
+        EXPECT_EQ(countEvent2, 1);
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 3; }));
+
+        eventFd2.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 2; }));
+    }
+
+    stop.store(true);
+    pollingThread.join();
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoPollingThreads) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd1(epoll_create(64));
+    base::unique_fd epollFd2(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd1.get(), 0);
+    ASSERT_GE(epollFd2.get(), 0);
+
+    // Register the same eventFd to two EpollFds.
+    ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    int countEpoll1 = 0;
+    int countEp